Cannot change frame of a UILabel in a UITableViewCell when first appearing (using Autolayout)
Asked Answered
R

9

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!

Rackety answered 8/1, 2014 at 12:51 Comment(2)
Have you found a solution to this problem?Daryl
Found Any solution for this problem ?Alec
S
9

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

Synsepalous answered 1/4, 2014 at 10:8 Comment(3)
That has resolved the issue but now I can't use AutoLayout. What is the wayout?Slum
Ok you are right.But i need to use auto layout on custom UITableViewCell,how to use?Grigg
If you want to use auto layout, what matters here are the constraints. Then you shouldn't change the frame. Please read this developer.apple.com/library/ios/documentation/UserExperience/…Synsepalous
B
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.

Brumbaugh answered 2/12, 2015 at 9:15 Comment(1)
The first solution definitely worked for me. Thanks!Rhyner
M
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.

Moldy answered 8/1, 2014 at 13:20 Comment(1)
Changing the frame of the label outside of the UITableView delegate calls does not make any difference. Are you using Autolayout as well?Rackety
A
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;
Amazing answered 8/1, 2014 at 12:55 Comment(0)
B
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;
Benue answered 8/1, 2014 at 12:55 Comment(3)
Thanks, but this only changes the size of the cell, not the size of the label the first time it is displayed.Rackety
yes do the same in cellForRowAtIndexPath and return cell rather then heightBenue
This doesn't work either. The first time the label appears it keeps the original size from the interface builder.Rackety
C
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;
Cerebrum answered 8/1, 2014 at 13:7 Comment(4)
Where should I put this code? cellForRowAtIndexPath? layoutSubviews inside the UITableViewCell?Rackety
cellForRowAtIndexPathCerebrum
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.Rackety
I think before setting text on label you have written the size code, you need to set the text in label at lastCerebrum
P
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

Perot answered 8/1, 2014 at 13:20 Comment(2)
I tried this and it hasn't helped. Are you using Autolayout as well?Rackety
No, i have not used autoLayout. i did code for complete app no Xib and Storyboard are used.Perot
C
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;
}
Cockburn answered 8/1, 2014 at 13:21 Comment(1)
This doesn't work for me. Are you using AutoLayout?Rackety
C
0

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

Instead, you should modify the constraints.

Chlorate answered 23/4, 2016 at 12:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.