3

I'm using a default UITableViewCell, just its textLabel. My text is multi-line. What's the best way to compute its height?

I know there are various NSString sizing methods, but in order to use those, you have to specify a width. And I don't know the width of the default textLabel, and I suspect it changes based upon which text is placed inside it.

I've tried also using the method described here:

Using Auto Layout in UITableView for dynamic cell layouts & variable row heights

...but it doesn't work (estimated size always comes back 0); there's an implication in that post that that solution only works for UITableViewCell subclasses. (I could subclass, but it's not necessary.)

Suggestions? My app is iOS 7-specific.

Thanks!

Community
  • 1
  • 1
Greg Maletic
  • 6,225
  • 8
  • 54
  • 73

3 Answers3

2

UITableView rowHeight property. If you do not explicitly set it, UITableView sets it to a standard value.

Marco
  • 6,692
  • 2
  • 27
  • 38
  • I think he is overriding `heightForRowAtIndexPath:` to set the height, but when following the example project and calling `CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;` height is 0 when using a standard `UITableViewCell`. I found the same thing when I tried as well. – ansible Feb 01 '14 at 22:58
2

I got it working with a standard UITableViewCell - using the github in the question you listed, but replace these functions.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil)
    {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
        cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
        cell.textLabel.numberOfLines = 0;
        cell.textLabel.font = [UIFont fontWithName:@"Helvetica" size:17.0];
    }

    // Configure the cell for this indexPath
    //[cell updateFonts];
    NSDictionary *dataSourceItem = [self.model.dataSource objectAtIndex:indexPath.row];
    cell.textLabel.text =[dataSourceItem valueForKey:@"body"];

    return  cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSDictionary *dataSourceItem = [self.model.dataSource objectAtIndex:indexPath.row];
    NSString *cellText = [dataSourceItem valueForKey:@"body"];

    UIFont *cellFont = [UIFont fontWithName:@"Helvetica" size:17.0];
    CGSize constraintSize = CGSizeMake(280.0f, MAXFLOAT);
    CGSize labelSize = [cellText sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];

    return labelSize.height;
}

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (self.isInsertingRow) {
        // A constraint exception will be thrown if the estimated row height for an inserted row is greater
        // than the actual height for that row. In order to work around this, we return the actual height
        // for the the row when inserting into the table view.
        // See: https://github.com/caoimghgin/TableViewCellWithAutoLayout/issues/6
        return [self tableView:tableView heightForRowAtIndexPath:indexPath];
    } else {
        return 500.0f;
    }
}

Oh also remove the register to the custom cell class so we get a UITableViewCell instead of RJTableViewCell. Also I think with this in here (even if it was a UITableViewCell) dequeueReusableCellWithIdentifier would never return nil and we wouldn't setup our cell correctly.

- (void)viewDidLoad
{
    [super viewDidLoad];

    //[self.tableView registerClass:[RJTableViewCell class] forCellReuseIdentifier:CellIdentifier];

    ...
}

Basically followed this example here - https://stackoverflow.com/questions/129502/how-do-i-wrap-text-in-a-uitableviewcell-without-a-custom-cell. I think the key is to not ask the cell for it's height like you do if you subclass the cell, but instead figure it out based on the text and font. The fact you can't ask the cell for it's hight seems a bit weird to me, and makes me think perhaps @Jeffery Thomas is right, it may be safer in the long run to just create a custom cell. Probably depends on your projet I would guess.

ansible
  • 3,569
  • 2
  • 18
  • 29
  • You're assuming the width is 280. Is that a valid assumption? (How wide are labels on iOS 7?) – Greg Maletic Feb 03 '14 at 18:53
  • I'm not 100% on that, that number came from the example linked. It should be easy to verify by checking it. And if you were really paranoid you could check the width for the first cell programmatically and cache it for ever other cell since it will always be the same in this example. – ansible Feb 03 '14 at 19:02
  • My concern is that maybe the width of textLabel changes dynamically based on the content, so I can't know the widest it gets even if I check it explicitly. Do we know it stays constant? – Greg Maletic Feb 03 '14 at 19:25
  • That would depend on if you support both landscape and portrait. Do you only text? Or is there an image? Is there always an image?... If your cell is simple, always text or always text and an icon, then I think this is a good approach. If is complicated and variable, then maybe a custom UITableViewCell would be better in your situation? Maybe there a better way, but if there is I'm not aware of it. – ansible Feb 03 '14 at 19:38
  • I think this method used to work before iPhone 6 and 6 plus have been released, when all iPhones were 320 points wide. This is not the case anymore. – almas Jan 30 '15 at 00:21
0

You need to subclass UITableViewCell.

You are asking more from UITableViewCell than it promises to provide. This is a recipe for trouble.

Create a subclass and build a prototype. You will know all the constraints, so this will be easy.

Jeffery Thomas
  • 42,202
  • 8
  • 92
  • 117