PDaria
PDaria

Reputation: 457

iOS the right way of heightForRowAtIndexPath calculation

I want to learn a common and right way of calculation of height for custom cells.
My cells are loaded from nib, they have two multiline UILabels one above other.
At the moment I create special configuration cell in viewDidLoad and use it in heightForRowAtIndexPath.

-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    [self configureCell:self.configurationCell forIndexPath:indexPath];
    CGRect configFrame = self.configurationCell.frame;
    configFrame.size.width = self.view.frame.size.width;
    self.configurationCell.frame = configFrame;

    [self.configurationCell layoutSubviews];

    UILabel *label = (UILabel *)[self.configurationCell viewWithTag:2];
    float height = label.frame.origin.y + label.frame.size.height + 10;

    return height;
}

It works but seems to be a bad manner. I think that heights must be precalculated for each item and for each orientation. But I can't find a way to make it nice and straightforward.
Could you help me?
Cell Label's style (like font and offsets from the screen borders) must be loaded from nib file (cell is inside nib).

Added cell's layourSubviews method:

-(void) layoutSubviews {

    [super layoutSubviews];

    [self.shortDescriptionLabel resize];

    CGRect longDescriptionFrame = self.longDescriptionLabel.frame;
    longDescriptionFrame.origin.y = self.shortDescriptionLabel.frame.origin.y + self.shortDescriptionLabel.frame.size.height + 5;
    self.longDescriptionLabel.frame = longDescriptionFrame;

    [self.longDescriptionLabel resize];
}

resize method of label simply increases it's height to fit all the text. So height of cell is calculated as longDescriptionLabel.bottom + 10. Simple code but not very beautiful.

Upvotes: 1

Views: 2838

Answers (1)

He Shiming
He Shiming

Reputation: 5819

It appears that you are trying to create subviews inside heightForRowAtIndexPath. View creation is supposed to be done in cellForRowAtIndexPath.

According to your implementation, you can only determine the height of the cell after it's been laid out. This is no good because UITableView calls heightForRowAtIndexPath for every cell, not just the visible ones upon data reload. As a result, subviews of all cells are created even if they aren't required to be visible.

To optimize this implementation, you have to work out some kind of formula to allow determination of height without laying out views. Even if your layout is elastic or has variable height, given text rectangle, you can still determine its height. Use [NSString sizeWithFont:] to determine its displayed rectangle. Record this information in your data delegate. When heightForRowAtIndexPath is called, return it directly.

Upvotes: 1

Related Questions