views:

1893

answers:

2

I've got some UITableViewCells that need to change their height depending on the length of the strings inside. I'm calculating the necessary height inside tableView:cellForRowAtIndexPath:, and then storing it in a variable (self.specialRowHeight). Then I've got:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == SPECIAL_SECTION) {
        return self.specialRowHeight;
    }
    else {
        return 44;
    }
}

Except that seems to be getting called before the tableView:cellForRowAtIndexPath: bit, so it's always zero.

Is there a way around this, or perhaps a different way to do it?

Thanks!

+2  A: 

Gonna answer my own question here:

Originally I was pretty sure that the height calculations were tied to the tableView:cellForRowAtIndexPath: method, and couldn't be moved elsewhere. With a bunch of restructuring, though, I was able to get that stuff out of there and into tableView:heightForRowAtIndexPath:, which solves everything.

For anyone else who's trying to get auto-height-adjusted cells to work, here's some code that might help:

// Inside tableView:cellForRowAtIndexPath:
cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
cell.textLabel.numberOfLines = self.numberOfTextRows;
// numberOfTextRows is an integer, declared in the class

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

    CGSize theSize = [theObject.theStringToDisplay sizeWithFont:[UIFont systemFontOfSize:18.0f] constrainedToSize:CGSizeMake(265.0f, 9999.0f) lineBreakMode:UILineBreakModeWordWrap];
    // This gets the size of the rectangle needed to draw a multi-line string
    self.numberOfTextRows = round(theSize.height / 18);
    // 18 is the size of the font used in the text label
    // This will give us the number of lines in the multi-line string

    if ((indexPath.section == FIXED_HEIGHT_SECTION) || (self.numberOfTextRows < 2)) {
        return 44;
        // 44 is the default row height; use it for empty or one-line cells (or in other table sections)
    } else {
        return theSize.height + 16;
        // 16 seems to provide a decent space above/below; tweak to taste
    }
}

If you can think of a more accurate way to calculate the proper cell height, I'm all ears. :)

Triz
I'm not really sure why you devide the rect height by 18 and then multiply it again, but other than that I do it pretty much the same way.
Daniel Rinser
Well, the first division is to find out how many rows are needed, so I can set `cell.textLabel.numberOfLines` correctly; if I don't set that, it all gets printed on one line. But yeah, I guess I could just use `theSize.height` in the last bit there, instead of `self.numberOfTextRows`.
Triz
Edited the answer for clarity and simplification. Works really well now.
Triz
cell.txtLabel.numberOfLines=0; //this will show all lines
Muxa
A: 

You could just set self.numberOfLines to 0 once and it would work the same. (If numberOfLines is set to 0 then the label uses as many rows as are needed.)

fonetik
Um... numberOfTextRows is a custom class property, so it won't do anything other than what I tell it to. Are you thinking of cell.textLabel.numberOfLines?
Triz
At any rate, yes, one can set `cell.textLabel.numberOfLines` to `0`, but it's still useful to find out the actual number that will be used (for calculating the appropriate row height, as here, for example). Also I find the resulting code to be much clearer, as "0" isn't at all semantically helpful at a glance.
Triz