5

I'm trying to calculate the height for a UITableViewCell so I've defined a class method that looks like this

+ (CGFloat)heightWithText:(NSString *)text
{
    SizingLabel.text = text;
    [SizingLabel sizeThatFits:CGSizeMake(LABEL_WIDTH, CGFLOAT_MAX)];

    return (TOP_MARGIN + SizingLabel.frame.size.height + BOTTOM_MARGIN);
}

I've defined SizingLabel like this:

+ (void)initialize
{
    SizingLabel = [[UILabel alloc] initWithFrame:CGRectZero];
    SizingLabel.numberOfLines = 0;
    SizingLabel.lineBreakMode = NSLineBreakByWordWrapping;
}

However, if i stick a breakpoint in the -heightWithText: method, i notice that the dimensions of SizingLabel never change and i thus get an incorrect value. Why is that?

Sean Danzeiser
  • 9,141
  • 12
  • 52
  • 90

5 Answers5

7

As said above, sizeThatFits: (and thus sizeToFit) do not work well with UILabel objects.

You better use the preferred textRectForBounds:limitedToNumberOfLines: method:

+ (CGFloat)heightWithText:(NSString *)text
{
    resizingLabel.text = text;
    CGSize labelSize = [resizingLabel textRectForBounds:CGRectMake(0.0, 0.0, LABEL_WIDTH, CGFLOAT_MAX)
                                 limitedToNumberOfLines:0].size; // No limit

    return (TOP_MARGIN + labelSize.height + BOTTOM_MARGIN);
}
Rivera
  • 10,792
  • 3
  • 58
  • 102
  • Does not work for me, also, you should follow the naming convention and start variable names with lower case (or is `SizingLabel` supposed to be a class?) – Daniel Nov 03 '14 at 14:48
  • `SizingLabel`must have been an automatic rename problem. Also you or anyone can edit posts ;) As for this not working. What part is the problem? Basically this code only uses the built-in `textRectForBounds:limitedToNumberOfLines:` which should always work. – Rivera Nov 04 '14 at 01:34
  • it was returning a size that did not really reflect the size the text would be given. After all, it does not take into account the font. I ended up using `NSString boundingRectWithSize:options:attributes:context:`. – Daniel Nov 04 '14 at 10:08
  • It does take into account the `UILabel` font and parameters. You can set it up all in IB and then have an accurate measure. That is why I prefer it than trying to recreate the label configuration with `NSString`. As for your problem, is the built-in method returning a wrong value or is it the accompanying adjustments? And the `SizingLabel` came from the original question. – Rivera Nov 05 '14 at 02:24
  • If you believe [this comment](http://stackoverflow.com/questions/14409897/how-to-calculate-the-height-of-an-nsattributedstring-with-given-width-in-ios-6#comment31619039_14410019), it seems that it does not work correctly when the attributed string does not contain a `NSFontAttributeName`. – Daniel Nov 10 '14 at 12:09
  • I've used sizeThatFits: for years, and it seems to be a bit of voodoo, sometimes works and sometimes just doesn't. Using textRectForBounds is perfect! – Darren Ehlers Sep 11 '18 at 16:43
5
+ (CGFloat)heightWithText:(NSString *)text
{
    SizingLabel.text = text;
    CGSize labelSize = [SizingLabel sizeThatFits:CGSizeMake(LABEL_WIDTH, CGFLOAT_MAX)];

    return (TOP_MARGIN + labelSize.height + BOTTOM_MARGIN);
}
OnkarK
  • 3,745
  • 2
  • 26
  • 33
3

Do this in your Custom Cell Class:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
    {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        // Initialization code

        //Message Label
        lbl_name = [[UILabel alloc]initWithFrame:CGRectMake(10, 10, 300, 25)];            

        [lbl_name setFont:[UIFont fontWithName:@"Helvetica" size:16.0f]];
        lbl_name.lineBreakMode = UILineBreakModeWordWrap;
        lbl_name.numberOfLines = 0;
        [lbl_name sizeToFit];
        [self.contentView addSubview:lbl_name];

        //Time 
    }
    return self;
}    

-(void)resizeNameLabel:(NSString *)text
{
    CGSize constraint = CGSizeMake(300 , 20000.0f);
    CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:16.0f] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
    [lbl_name setFrame:CGRectMake(10, 5, 300, MAX(size.height, 25.0f))];//300 Label Width
    [lbl_name setText:text];
}

Do this in main class..

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

    if (cell == nil) 
    {
        cell = (CustomCell *)[[CustomCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"cell"];
    }
        [((CustomCell *)cell) resizeNameLabel:text];

    return cell;
}

Just do like this...

Daniel
  • 20,420
  • 10
  • 92
  • 149
TamilKing
  • 1,643
  • 1
  • 12
  • 23
0

below code is to calculate the rect for dynamic text length (ios7 version)

- (CGRect)labelFrameWithText:(NSString *)text
{
    CGRect rect;

    // the font of your text
    UIFont *font = [UIFont systemFontOfSize:15.0]; 
    NSDictionary *attributes = @{NSFontAttributeName: font};

    // the first parametric CGSize is the max size that the rect's size can be
    CGRect boundingRect = [text boundingRectWithSize:CGSizeMake(youImageWidth, 100.0)
                                              options:NSStringDrawingUsesLineFragmentOrigin
                                           attributes:attributes
                                              context:nil];

    //the rect of the UILabel
    //This method returns fractional sizes (in the size component of the returned CGRect); to use a returned size to size views, you must use raise its value to the nearest higher integer using the ceil function.
    rect = CGRectMake(yourLabelOriginX,
                      yourLabelOriginY,
                      ceil(boundingRect.size.width),
                      ceil(boundingRect.size.height));

    return rect;
}

and after you get the rect, use it to calculate your cell size

----------------older version-------------------

CGSize contentSize = [content sizeWithFont:font
                             constrainedToSize:CGSizeMake(maxWidth, maxHeight)
                                 lineBreakMode: NSLineBreakByWordWrapping];
Jing
  • 536
  • 3
  • 12
0

For simple sizing of UILabels that have attributed text, I added this category to UILabel.

@implementation UILabel (PAUtils)

- (CGSize)jb_attributedSizeThatFits:(CGSize)size
{
    CGRect textRect = [self.attributedText boundingRectWithSize:size options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) context:nil];
    return textRect.size;
}

@end

Two things to note:

  1. When not setting attributedText (but instead just using text) this method doesn't take into account the numberOfLines property.
  2. boundingRectWithSize returns fractions of points. If you are using the values returned from this method for layouts, you should probably ceilf the width and height.
johnboiles
  • 3,494
  • 1
  • 32
  • 26