Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IOS: dynamic height with a custom uitableviewcell

I am new at ios development and this is my problem thus far. I am able to dynamically calculate the height of a custom cell via the delegate "heightForRowAtIndexPath". So on the first load, every thing is display perfectly fine.

My problem is as soon as I start scrolling, everything just messes up. I think that while scrolling the "heightForRowAtIndexPath" is no longer called per cell that get display on screen, so the new cell height cannot be calculated.

So I've been stuck here for a while. I was wondering if any of you could lend me a hand. thank you in advance.

I'll post the code to relevant files. These files include the custom cell h and m file. and relevant functions of the view controller m file.

// ######################################################
// HelpTableViewCell.h
#import <UIKit/UIKit.h>

@interface HelpTableViewCell : UITableViewCell  {
  IBOutlet UILabel *labelName;
  IBOutlet UILabel *labelDescription;

  IBOutlet UIView *viewBackground;
}

@property (nonatomic, retain) UILabel *labelName;
@property (nonatomic, retain) UILabel *labelDescription;

@property (nonatomic, retain) UIView *viewBackground;

@end

// ######################################################
// HelpTableViewCell.m
#import "HelpTableViewCell.h"

@implementation HelpTableViewCell

@synthesize labelName;
@synthesize labelDescription;

@synthesize viewBackground;

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
  self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];

  if (self) {
  }

  return self;
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated  {

  self.labelName.lineBreakMode = UILineBreakModeWordWrap;
  self.labelName.numberOfLines = 0;
  self.labelName.font = [UIFont boldSystemFontOfSize:15];
  [self.labelName sizeToFit];

  self.labelDescription.lineBreakMode = UILineBreakModeWordWrap;
  self.labelDescription.numberOfLines = 0;
  self.labelDescription.font = [UIFont fontWithName:@"Arial" size:15];
  [self.labelDescription sizeToFit];

  [super setSelected:selected animated:animated];
}

- (void) dealloc  {
  [labelName release], labelName = nil;
  [labelDescription release], labelDescription = nil;

  [super dealloc];
}

@end


// ######################################################
// in my view controller m file
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath  {  
  static NSString *CellIdentifier = @"HelpTableViewCell";
  HelpTableViewCell *cell = (HelpTableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

  if (cell == nil)  {
    NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"HelpTableViewCell" owner:nil options:nil];

    for (id currentObject in topLevelObjects) {
      if ([currentObject isKindOfClass:[UITableViewCell class]])  {
        cell = (HelpTableViewCell *) currentObject;
        break;
      }
    }

  }

  cell.labelName.text = [self.instructionName objectAtIndex:indexPath.row];
  cell.labelDescription.text = [self.instructionDescription objectAtIndex:indexPath.row];

  return cell;
}

- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *cellText = [self.instructionDescription objectAtIndex:indexPath.row];
    UIFont *cellFont = [UIFont fontWithName:@"Arial" size:15];
    CGSize constraintSize = CGSizeMake(320.0f, MAXFLOAT);
    CGSize labelSize = [cellText sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];

    return labelSize.height + 25;  
}
like image 348
Daniel Nguyen Avatar asked Aug 19 '11 22:08

Daniel Nguyen


2 Answers

If the text in the cells is going to change, you will need to a call reloadData on your tableView when it does, otherwise the tableView:heightForRowAtIndexPath: won't be called.

The way the tableView works is that it gathers the heights for all rows at every reload (and the reload variants). This is how iOS knows the height of the entire table. It doesn't call tableView:heightForRowAtIndexPath: again when grabbing individual cells. Usually calling reloadData is quite quick and this method, unlike its variants, doesn't cause any scrolling.

See stackoverflow question and answer for useful background.

Problems arise if you have to do a lot of work to calculate heights and you have hundreds or thousands of rows. In one use case I have like this, I cache the row height calculations to get decent performance. But if that's not your case, just be a little more liberal with reloadData.

like image 182
Obliquely Avatar answered Sep 21 '22 17:09

Obliquely


There is a good tutorial that walks you through the process of determining the height that is required to fit your text and sizing the cell height appropriately.

the tutorial is available here: http://www.raddonline.com/blogs/geek-journal/iphone-sdk-resizing-a-uitableviewcell-to-hold-variable-amounts-of-text/

I have not attempted the methods in the tutorial myself, but it looks to be pretty thorough.

Hope this helps!

like image 29
superjessi Avatar answered Sep 19 '22 17:09

superjessi