8

There are many solutions out there that use "sizeWithFont" or something similar, which happens to be deprecated as of iOS 7.

Here is some code I have pieced together so far. The height changes, but not at all accurately:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

// Configure the cell...
cell.textLabel.text = "The Cell's Text!";
cell.textLabel.numberOfLines = 0;
[cell.textLabel setLineBreakMode:NSLineBreakByWordWrapping];
[cell.textLabel sizeToFit];

return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
CGRect screenBounds = [[UIScreen mainScreen] bounds];
CGSize screenSize = screenBounds.size;

NSAttributedString *aString = [[NSAttributedString alloc] initWithString:"The Cell's Text!"];
UITextView *calculationView = [[UITextView alloc] init];
[calculationView setAttributedText:aString];
CGSize size = [calculationView sizeThatFits:CGSizeMake(screenSize.width, FLT_MAX)];
return size.height;
}

For another example, here's a similar answer: https://stackoverflow.com/a/9828777/693121 though as I said before, this utilizes deprecated code.

Community
  • 1
  • 1
Demasterpl
  • 2,037
  • 4
  • 24
  • 32

5 Answers5

14

You should use the method that's mentioned in the docs to replace the old one -- boundingRectWithSize:options:attributes:context:. Here's an example that I think should work (it works with multi-line labels anyway).

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSStringDrawingContext *ctx = [NSStringDrawingContext new];
    NSAttributedString *aString = [[NSAttributedString alloc] initWithString:@"The Cell's Text!"];
    UITextView *calculationView = [[UITextView alloc] init];
    [calculationView setAttributedText:aString];
    CGRect textRect = [calculationView.text boundingRectWithSize:self.view.frame.size options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:calculationView.font} context:ctx];
        return textRect.size.height;
  }

This assumes that you want the text view to be the size of self.view. If not, you should use initWithFrame for your text view, and pass calculationView.frame.size for the boundingRectWithSize: parameter.

codercat
  • 21,439
  • 9
  • 56
  • 84
rdelmar
  • 102,832
  • 11
  • 203
  • 218
  • For some reason this always returns a height of 13.8? Regardless of the amount of text in "aString" variable. – Demasterpl Nov 27 '13 at 13:46
  • 1
    @Demasterpl, sorry, I used the wrong options parameter in my answer, it should be NSStringDrawingUsesLineFragmentOrigin. I've corrected my answer. – rdelmar Nov 27 '13 at 16:18
  • That seems to be returning a respectable value, although sometimes even though the height is a large number, it still appears to maintain default height. Also, it didn't seem to make a difference if I removed cell properties (like sizeToFit & setLineBreakMode). :( – Demasterpl Nov 27 '13 at 16:31
  • @Demasterpl,, what maintains the default height? The cell, or the text view? – rdelmar Nov 27 '13 at 16:35
  • Sorry to take to long to reply, but it all appears to be random. I can't nail down what's consistent. – Demasterpl Jan 06 '14 at 15:42
  • can you please answer the question on this link http://stackoverflow.com/questions/21155143/nscfstring-boundingrectwithsizeoptionsattributescontext-unrecognized-s – PK86 Jan 16 '14 at 07:27
  • I get a 'unrecognized selector sent to instance' error on the boundingRecWithSize call. – Chase Roberts Feb 06 '14 at 23:50
  • @ChaseRoberts, what is the full error message, and what version of iOS are you building for? – rdelmar Feb 06 '14 at 23:54
  • 1
    I have NSStringDrawingUsesLineFragmentOrigin in there and I'm still getting the 13.8 that @Demasterpl was getting. – Marcel Marino Mar 10 '15 at 16:04
8

This here is the easiest version, iOS 7 does all the heavy lifting (only for autolayout-based uitableviewcells):

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
   CustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: @"Cell"];

   [self configureCell:cell];

   // edit: Need to call [cell layoutIfNeeded]; otherwise the layout changes wont be applied to the   cell

   [cell layoutIfNeeded];


   return [cell.contentView systemLayoutSizeFittingSize: UILayoutFittingCompressedSize].height;
}

systemLayoutSizeFittingSize re-evaluates the autolayout constraints and returns the perfect height for your cell. Easy, right?

Wirsing
  • 6,104
  • 3
  • 13
  • 13
  • what does the method [self configureCell:cell]; ? – MiQUEL Apr 12 '14 at 19:50
  • basic setup of the cell dependent of the data object (e.g., setting labels). with it i "fill" the cell with content, thus autolayout can determine the required height automatically – Wirsing May 09 '14 at 13:02
2

I got it from my colleague (ANIRUDH) and working fine, may be helpful:

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

//Calculating height on base of length of text
    UIFont *font =  [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
    NSAttributedString *attributedText =
    [[NSAttributedString alloc]
     initWithString:YOURSTRING //[NSString string withformat:@"\n Yourstring"] \n for: number of lines require for static label in cell
     attributes:@
     {
     NSFontAttributeName: font
     }];
    CGRect rect = [attributedText boundingRectWithSize:(CGSize){CELL_CONTENT_WIDTH, CGFLOAT_MAX}
                                               options:NSStringDrawingUsesLineFragmentOrigin
                                               context:nil];
    CGSize size = rect.size;

    //  NSString *height = [NSString stringWithFormat: @"%.2f", ceilf(size.height)+22];
    return (ceilf(size.height)+22)*0.6; //change 0.6 to 0.9 according to the difference in required and extra calculted height, it works for me every time
}
Yogesh Lolusare
  • 2,094
  • 1
  • 21
  • 35
0
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *yourText = [[resultArray objectAtIndex:indexPath.row] valueForKey:@"review_text"];
    CGSize lblwidth = CGSizeMake(300, CGFLOAT_MAX);
    CGSize requiredSize = [yourText sizeWithFont:[UIFont fontWithName:@"CALIBRI" size:17] constrainedToSize:lblwidth lineBreakMode:NSLineBreakByWordWrapping];
    int calculatedHeight = requiredSize.height+50;
    return (float)calculatedHeight;
}
kalpesh
  • 1,212
  • 1
  • 16
  • 27
-1

To get the size of your string you should use - (CGSize)sizeWithAttributes:(NSDictionary *)attars.

So for your example you would calculate the height of the text label as such:

CGSize *cellSize = [cell.textLabel.text sizeWithAttributes:@{NSFontAttributeName:[cell.textLabel.font]}];

or

CGSize *rowSize = [aString sizeWithAttributes:nil];
  • 3
    This will not work. From Apple's docs: "Returns the size of the string if it were to be rendered with the specified font on a single line." That's not useful if you're trying to change cell height based on a multi-line label. – rdelmar Nov 26 '13 at 00:16