Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to programmatically increase UITableView cell's height in iPhone?

I having the separate custom UITableViewCell for displaying the data(these data come from server JSON response).In each UITableViewCell i am having button as read more.If the user clicks read more button i want to programmatically add UILabel for displaying additional information from server.But initially i set UITableViewCell height so after clicking read more button i cant able to see the additional inforamtion UILabel..

This is the screen shot:

enter image description here

This is my required screen:

enter image description here

This is the following coding i used:

-(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{

   int height1;
    if(readMore){
        height1=200;
        NSLog(@"Clicked");
    }
    else{
        height1=100;
        NSLog(@"Not clicked");
    }
    return height1; // Normal height
}


-(NSInteger) tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section
{
    return [TitleArr  count];
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
    {
        static NSString *simpleTableIdentifier = @"SimpleTableCell_iPad";

        cell = (TableCell_Leads *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
    }
    else{
        static NSString *simpleTableIdentifier = @"TableCell_Leads";

        cell = (TableCell_Leads *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
    }
    if (cell == nil)
    {
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
        {
            NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"SimpleTableCell_iPad" owner:self options:nil];
            cell = [nib objectAtIndex:0];

        }
        else{
            NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"TableCell_Leads" owner:self options:nil];
            cell = [nib objectAtIndex:0];
        }
    }




    cell.labTitle.text = [TitleArr objectAtIndex:indexPath.row];

    cell.labCategory.text=[CategoryArr objectAtIndex:indexPath.row];

    [cell.btnReadmore addTarget:self
                         action:@selector(funReadmore:)
               forControlEvents:UIControlEventTouchUpInside];


    return cell;
}



 - (IBAction)funReadmore:(id)sender
    {
        [self.tableView beginUpdates];
        readMore=TRUE;



        NSLog(@"READ MORE");
        [self.tableView endUpdates];
}
like image 419
Kalai Avatar asked Jan 28 '14 04:01

Kalai


3 Answers

First of all take a bool & int variable.

BOOL isReadMoreButtonTouched = NO;
int indexOfReadMoreButton = -1;

Then Implement below with your code

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    [[cell btnReadmore] setTag:[indexPath row]];

    if(isReadMoreButtonTouched && [indexPath row]== indexOfReadMoreButton)
    {
       // design your read more label here
    }
}

Now implement IBAction

-(IBAction) funReadmore:(id)sender
{
    UIButton *readMoreButton = (UIButton *)sender;
    indexOfReadMoreButton=[readMoreButton tag];
    isReadMoreButtonTouched=YES;

    [[self tableView] beginUpdates];
    [[self tableView] reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForItem: indexOfReadMoreButton inSection:0]] withRowAnimation:UITableViewRowAnimationAutomatic];
    [[self tableView] endUpdates];
}

Now Come to heightForRowAtIndexPath

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if(isReadMoreButtonTouched && [indexPath row]== indexOfReadMoreButton) return 200.0f;
    else return 100.0f;
}

Hope it'll work for you.

like image 132
Tapas Pal Avatar answered Oct 12 '22 20:10

Tapas Pal


Take a int readMoreAtIndex; as your class variable. Initialize it with a negative value like -1 in init method and/or viewDidLoad/viewWillAppear. Some basic logic would be like this:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{   
    if(readMoreAtIndex == indexPath.row) {
        return 400; //return as per your requirement
    }
    return 100;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    //same lines as currently you are doing to setup cell.     

    //important line
    [cell.btnReadmore setTag:indexPath.row];

    [cell.btnReadmore addTarget:self
                         action:@selector(funReadmore:)
               forControlEvents:UIControlEventTouchUpInside];

    if(indexPath.row == readMoreAtIndex) {
        //setup your cell according to your logic to show expanded view
    }
    else {
        //you are reusing cells, so provide logic to disappear shown expanded view if you want
    }

    return cell;
}

- (IBAction)funReadmore:(id)sender
{     
    UIButton *button = (UIButton *)sender;
    readMoreAtIndex = button.tag;
    [yourTableView reloadData];
    NSLog(@"READ MORE");
}

EDIT: Links for tutorials to implement expandable/collapsable tableview.

  1. Expanding/Collapsing TableView Sections
  2. Collapsable Table View for iOS
like image 4
Salman Zaidi Avatar answered Oct 12 '22 20:10

Salman Zaidi


I found another solution based on self-sizing table view cells. Instead of updating cell's height (hardcoded) we can update the constraints priority.

fileprivate extension Int {
   static let rowHeight = 175
}

class CellArticleData {
  var article: Article
  var isExpanded: Bool

  init(article: Article, isExpanded: Bool) {
    self.article = article
    self.isExpanded = isExpanded
  }
}

 enum Article: String {
    case medicine, sport
    static let allArticles: [Article] = [.medicine, .sport]
    var title: String { return self.rawValue.capitalized }
    var description: String {
        switch self {
          case .medicine:
            return "Lorem Ipsum is simply dummy text of the printing and 
            typesetting industry"
          case .sport:
            return "Contrary to popular belief, Lorem Ipsum is not simply 
            random text. It has roots in a piece of classical Latin 
            literature from 45 BC, making it over 2000 years old. Richard 
            McClintock, a Latin professor at Hampden-Sydney College in 
            Virginia."
      }
   }
}

class ViewController: UIViewController {

@IBOutlet weak var tableView: UITableView!
var articles: [CellArticleData] = Article.allArticles.map { CellArticleData(article: $0, isExpanded: false) }

override func viewDidLoad() {
    super.viewDidLoad()

    tableView.dataSource = self
    tableView.delegate = self
    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.estimatedRowHeight = CGFloat(.rowHeight)
}

 extension ViewController: UITableViewDataSource {

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! MyCell
    let articleData = articles[indexPath.row]
    cell.setup(articleData: articleData)
    cell.delegate = self
    return cell
  }
}

extension ViewController: MyCellDelegate {

  func handleReadMore() {
      tableView.reloadData()
   }
}

I have a custom class that represent a cell "MyCell" which handles the protocol and constraints updates:

protocol MyCellDelegate {
    func handleReadMore()
}

class MyCell: UITableViewCell {

   @IBOutlet weak var topConstraint: NSLayoutConstraint!
   @IBOutlet weak var bottomConstraint: NSLayoutConstraint!
   @IBOutlet weak var heightConstraint: NSLayoutConstraint!

  func setup(articleData: CellArticleData) {
    self.articleData = articleData

    titleLabel.text = articleData.article.title
    descriptionLabel.text = articleData.article.description
    readMoreLabel.isUserInteractionEnabled = true

    let readMoreTap = UITapGestureRecognizer(target: self, action: #selector(handleReadMore))
    readMoreTap.cancelsTouchesInView = false
    readMoreLabel.addGestureRecognizer(readMoreTap)
    updateCellConstraints()
}

fileprivate func updateCellConstraints() {
    if let articleData = self.articleData {
        if !articleData.isExpanded {
            heightConstraint.priority = 999
            topConstraint.priority = 250
            bottomConstraint.priority = 250
        }else {
            heightConstraint.priority = 250
            topConstraint.priority = 999
            bottomConstraint.priority = 999
        }

    }
  }

   func handleReadMore() {
      if let articleData = self.articleData {
         articleData.isExpanded = !articleData.isExpanded
         delegate?.handleReadMore(articleData: articleData)
     }
   }
}

Here is an example showing how it looks like: My custom cell MyCell

like image 2
Martin Deandreis Avatar answered Oct 12 '22 20:10

Martin Deandreis