7

I have a prototype cell inside my UITableView which contains a UILabel. I want to dynamically change the size of the label (and the cell) depending on the size of the text in the label.

I create the prototype cell in cellForRowAtIndexPath like this:

static NSString *CellIdentifier = @"ProgramDetailCell";
ProgramDetailCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.descriptionLabel.text = self.program.subtitle;
return cell;

Then my ProgramDetailCell has the following implementation:

@implementation ProgramDetailCell
- (void)layoutSubviews {
    [super layoutSubviews];
    [self.descriptionLabel sizeToFit];
}
@end

The first time the cell is displayed, layoutSubviews is called, but the descriptionLabel does not get resized. However, if I scroll down the table and back up again, the "reused" cell appears with the label correctly resized!

Why does it not work the first time the cell is displayed - and what do I need to do to fix it.

Thanks in advance!

theDuncs
  • 4,649
  • 4
  • 39
  • 63

9 Answers9

9

In xib, go to first tab, under Interface Builder Document , uncheck use Auto Layout box.

Yllow
  • 326
  • 4
  • 7
  • That has resolved the issue but now I can't use AutoLayout. What is the wayout? – Developer Jul 24 '15 at 07:58
  • Ok you are right.But i need to use auto layout on custom UITableViewCell,how to use? – IKKA Aug 06 '15 at 10:22
  • If you want to use auto layout, what matters here are the constraints. Then you shouldn't change the frame. Please read this https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/WorkingwithConstraintsinInterfaceBuidler.html – Yllow Feb 05 '16 at 04:21
4

It doesn't work because you are using auto layout. You need some auto layout way to achieve this.

Here's the solution.

Step 1 :

Have the UILabel Pinned to Top and Bottom of the UITableViewCell. You can achieve this through the Interface Builder by having Vertical Constraint on UILabel from top and bottom of the cell. This will make the UILabel increase in height if the cell's height increase or vice versa.

Step 2:

In your UIViewController in - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath method calculate the size of the UITableViewCell.

You can calculate it using :

 CGRect textFrame = [YourText boundingRectWithSize:CGSizeMake(width of the label, FLT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:Your Font} context:nil];

now return the textFrame.size.height + padding if present.

Step 3 :

You will achieve what you wanted --- "dynamically change the size of the label (and the cell) depending on the size of the text in the label" after compiling and running even for the first time.

Sarasranglt
  • 3,819
  • 4
  • 23
  • 36
2

After retrieving all data from server you can get height of that UILabel using this method.

CGSize maximumSize = CGSizeMake(210, 9999);
for (int i = 0; i < [_arrProductList count]; i++) {

      float row_height = 0.0f;

      ProductInformation *product_obj = [_arrProductList objectAtIndex:i];
      CGSize desc_size = [self measureHeightForText:product_obj.product_desc forFont:   [UIFont systemFontOfSize:14] forSize:maximumSize];

      row_height = row_height + desc_size.height;

   //   [_arrRowHeights addObject:[NSString stringWithFormat:@"%f", row_height]]; You can take it into array.

}

[tableView reloadData];

And here i have given description of measureHeightForText:. This logic is working in all iOS5,iOS6,iOS7.

-(CGSize)measureHeightForText:(NSString *)strText forFont:(UIFont *)font forSize:(CGSize)size{

    if (!testingLabel) {

        testingLabel = [[UILabel alloc] init];
        // testingLabel.font = [UIFont fontWithName:[AppHandlers zHandler].fontName size:16];
        testingLabel.text = @"";
        testingLabel.numberOfLines = 0;

    }

    testingLabel.text =strText;
    testingLabel.font = font;
    CGSize expectedSize = [testingLabel sizeThatFits:size];
    return expectedSize;
}

And then update size of your label according it. This is working fine for me. I am using it.

Nirav Jain
  • 5,088
  • 5
  • 40
  • 61
  • Changing the frame of the label outside of the UITableView delegate calls does not make any difference. Are you using Autolayout as well? – theDuncs Jan 08 '14 at 14:01
1

Because when layoutSubviews is called your descriptionLabel's text is not set yet. And when you scroll, the text is set. So it is correct now.

I suggest you call sizeToFit after you set the text.

static NSString *CellIdentifier = @"ProgramDetailCell";
ProgramDetailCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.descriptionLabel.text = self.program.subtitle;
[cell.descriptionLabel sizeToFit];
return cell;
sunkehappy
  • 8,970
  • 5
  • 44
  • 65
1

Call this in heightForRowAtIndexPath and manually calculate the height

static NSString *CellIdentifier = @"ProgramDetailCell";
ProgramDetailCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.descriptionLabel.text = self.program.subtitle;
[cell.descriptionLabel sizeToFit];

return cell.descriptionLabel.frame.size.height+cell.descriptionLabel.frame.origin.y;
Jay Gajjar
  • 2,661
  • 2
  • 21
  • 35
1

You can use below code:

//Calculate the expected size based on the font and linebreak mode of your label
// FLT_MAX here simply means no constraint in height
CGSize maximumLabelSize = CGSizeMake(296, FLT_MAX);

CGSize expectedLabelSize = [yourString sizeWithFont:yourLabel.font constrainedToSize:maximumLabelSize lineBreakMode:yourLabel.lineBreakMode];   

//adjust the label the the new height.
CGRect newFrame = yourLabel.frame;
newFrame.size.height = expectedLabelSize.height;
yourLabel.frame = newFrame;
Ashutosh
  • 2,215
  • 14
  • 27
  • Where should I put this code? cellForRowAtIndexPath? layoutSubviews inside the UITableViewCell? – theDuncs Jan 08 '14 at 13:08
  • cellForRowAtIndexPath – Ashutosh Jan 08 '14 at 13:10
  • Thanks, but that didn't work. The size of the frame is the same as in the IB when it first appears, and only changes to the new size once the cell is redisplayed after scrolling. – theDuncs Jan 08 '14 at 13:15
  • I think before setting text on label you have written the size code, you need to set the text in label at last – Ashutosh Jan 08 '14 at 13:25
1

If your requirement is dynamically changing label height mean follow the below link. When we need to change height of label we need to change the row height also:

Resizing UILabel not quite working

Community
  • 1
  • 1
Charan Giri
  • 1,097
  • 1
  • 9
  • 15
0

Use below code for dynamic height set in cell

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

    NSString *messagetext=[NSString stringWithFormat:@"%@",[[arryStoryView objectAtIndex:indexPath.row] valueForKey:@"messagetext"]];

    CGSize StoryTextSize= [messagetext sizeWithFont:[UIFont fontWithName:@"Georgia" size:17.0f] constrainedToSize:CGSizeMake(300, MAXFLOAT) lineBreakMode:NSLineBreakByWordWrapping];

    int TotalHeight;
    TotalHeight= StoryTextSize.height + 10; 

    return TotalHeight;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

    static NSString *CellIdentifier = @"Cell1";
    UITableViewCell *cell=[tblSendMsg dequeueReusableCellWithIdentifier:CellIdentifier];

    cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault
                                 reuseIdentifier:CellIdentifier];
    cell.selectionStyle = UITableViewCellSelectionStyleNone;
    NSString *storytext=[NSString stringWithFormat:@"%@",[[arryStoryView objectAtIndex:indexPath.row] valueForKey:@"storytext"]];

    CGSize StoryTextSize = [storytext sizeWithFont:[UIFont fontWithName:@"Georgia" size:17.0f] constrainedToSize:CGSizeMake(300, MAXFLOAT) lineBreakMode:NSLineBreakByWordWrapping];
    lblStoryText.frame=CGRectMake(5, 25, [[UIScreen mainScreen] bounds].size.width-10, StoryTextSize.height+30);

    int nooflines=StoryTextSize.height/16;
    int i= StoryTextSize.height;
    if(i%16 !=0)
    {
        nooflines=nooflines+1;
    }

    lblStoryText.numberOfLines=nooflines;
    lblStoryText.font=[UIFont fontWithName:@"Georgia" size:17.0f];
    lblStoryText.text=[NSString stringWithFormat:@"%@",storytext];

    return cell;
}
Pradhyuman sinh
  • 3,936
  • 1
  • 23
  • 38
0

If you are using autolayout, modifying the frame will have no effect.

Instead, you should modify the constraints.

Rachit Rawat
  • 2,410
  • 3
  • 19
  • 30