Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling heightForRowAtIndexPath from within cellForRowAtIndexPath?

So, it seems that heightForRowAtIndexPath is called before cellForRowAtIndexPath. I'm currently using cellForRowAtIndexPath to calculate the height of each cell (they're variable heights, using a UILabel with varying amounts of text in it.

I'm puzzled as to exactly how I can set the cell's height correctly if the method that sets the height is called before the method that calculates it.

I've created a category of NSString, and another of UILabel, which working together make the UILabel the right size. The issue is that the UITableViewCell instances which contain those labels aren't being resized, so the labels hang over the end of each label, overlapping the ones beneath.

I know that what I need to do is make the height of the cell equal the height of the label, plus some extra margin space, but I'm puzzled as to how I can set the height before the label height has been calculated. Can I set the height someone without using heightForRowAtIndexPath? Or if not, could I calculate the height of the cell elsewhere? I'm currently using indexPath.row to make that happen, so doing it beforehand would be tricky. Here's the code my cellForRowAtIndexPath:

cellForRowAtIndexPath

- (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath
{
    FQCustomCell *_customCell = [tableView dequeueReusableCellWithIdentifier: @"CustomCell"];
    if (_customCell == nil) {
        _customCell = [[FQCustomCell alloc] initWithStyle: UITableViewCellStyleValue1 reuseIdentifier: @"CustomCell"];
    }

    _customCell.myLabel.text = [[_loadedNames objectAtIndex: indexPath.row] name];
    _customCell.myLabel.font = [UIFont fontWithName: @"FontA" size: 15.0f];

    UIView *backView = [[UIView alloc] initWithFrame: CGRectZero];
    backView.backgroundColor = [UIColor clearColor];
    _customCell.backgroundView = backView;

    _customCell.myLabel.frame = CGRectMake(5, 5, 265, 65);

    [_customCell.myLabel sizeToFitMultipleLines];
    return _customCell;
}
like image 980
Luke Avatar asked Feb 19 '13 11:02

Luke


2 Answers

You need to calculate the height of the cell in heightForRowAtIndexPath, something like

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *theText=[[_loadedNames objectAtIndex: indexPath.row] name];
    CGSize labelSize = [theText sizeWithFont:[UIFont fontWithName: @"FontA" size: 15.0f] constrainedToSize:kLabelFrameMaxSize];
    return kHeightWithoutLabel+labelSize.height;
}

You can set some constraints on the label size by setting kLabelFrameMaxSize

#define kLabelFrameMaxSize CGSizeMake(265.0, 200.0)

Then you return the height by adding a constant height with the variable label height.

Also, to be consistent, you should use the same methodology to set the frame in cellForRowAtIndexPath instead of using sizeToFitMultipleLines

- (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath
{
    FQCustomCell *_customCell = [tableView dequeueReusableCellWithIdentifier: @"CustomCell"];
    if (_customCell == nil) {
        _customCell = [[FQCustomCell alloc] initWithStyle: UITableViewCellStyleValue1 reuseIdentifier: @"CustomCell"];
    }

    _customCell.myLabel.text = [[_loadedNames objectAtIndex: indexPath.row] name];
    _customCell.myLabel.font = [UIFont fontWithName: @"FontA" size: 15.0f];

    UIView *backView = [[UIView alloc] initWithFrame: CGRectZero];
    backView.backgroundColor = [UIColor clearColor];
    _customCell.backgroundView = backView;

    CGSize labelSize = [_customCell.myLabel.text sizeWithFont:_customCell.myLabel.font constrainedToSize:kLabelFrameMaxSize];
    _customCell.myLabel.frame = CGRectMake(5, 5, labelSize.width, labelSize.height);

    return _customCell;
}
like image 77
JP Hribovsek Avatar answered Oct 22 '22 02:10

JP Hribovsek


You should calculate the height of the cell in heightForRowAtIndexPath method. It should be done without using any UILabel, just like heightForRowAtIndexPath implementation in JP Hribovsek's answer.

Then in cellForRowAtIndexPath do not set the frame of any subviews and do not call sizeToFitMultipleLines method of the label. Instead, implement layoutSubviews method of FQCustomCell such that the subview frames are set correctly for any possible bounds of the cell. You should't care about the text or font size in this method, just make sure the margins of the label are correct. If the height of the cell is calculated correctly in heightForRowAtIndexPath method, the size of your labels will be just right.

like image 25
murat Avatar answered Oct 22 '22 01:10

murat