83

In iOS7, sizeWithFont is deprecated, so I am using boundingRectWithSize(which returns a CGRect value). My code:

 UIFont *fontText = [UIFont fontWithName:[AppHandlers zHandler].fontName size:16];
                    // you can use your font.

 CGSize maximumLabelSize = CGSizeMake(310, 9999);

 CGRect textRect = [myString boundingRectWithSize:maximumLabelSize   
                             options:NSStringDrawingUsesLineFragmentOrigin
                             attributes:@{NSFontAttributeName:fontText}
                             context:nil];

 expectedLabelSize = CGSizeMake(textRect.size.width, textRect.size.height);

In textRect, I'm getting a size greater than my maximumLabelSize, a different size than when using sizeWithFont. How can I resolve this issue?

Tom Howard
  • 4,672
  • 2
  • 43
  • 48
Nirav Jain
  • 5,088
  • 5
  • 40
  • 61

6 Answers6

152

How about create new label and using sizeThatFit:(CGSize)size ??

UILabel *gettingSizeLabel = [[UILabel alloc] init];
gettingSizeLabel.font = [UIFont fontWithName:@"YOUR FONT's NAME" size:16];
gettingSizeLabel.text = @"YOUR LABEL's TEXT";
gettingSizeLabel.numberOfLines = 0;
gettingSizeLabel.lineBreakMode = NSLineBreakByWordWrapping;
CGSize maximumLabelSize = CGSizeMake(310, CGFLOAT_MAX);

CGSize expectSize = [gettingSizeLabel sizeThatFits:maximumLabelSize];

Edit: This upper code is not good for ios 7 and above, so please use below:

CGRect textRect = [myString boundingRectWithSize:maximumLabelSize   
                         options:NSStringDrawingUsesLineFragmentOrigin| NSStringDrawingUsesFontLeading
                         attributes:@{NSFontAttributeName:fontText}
                         context:nil];
Quang Hà
  • 4,613
  • 3
  • 24
  • 40
37

Maybe you need to provide additional option to the method that is suggested in this answer:

CGSize maximumLabelSize = CGSizeMake(310, CGFLOAT_MAX);
CGRect textRect = [myString boundingRectWithSize:maximumLabelSize   
                                         options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                      attributes:@{NSFontAttributeName: fontText}
                                         context:nil];
Community
  • 1
  • 1
Maxim Pavlov
  • 2,962
  • 1
  • 23
  • 33
  • 3
    It looks like the `boundingRectWithSize` is broken. I tested on iOS 7, 7.1.1 and it returns not correct results. – Rafał Sroka Apr 29 '14 at 10:57
  • This did not work for me, however using boundingRectWithSize on an NSAttributedString and adding my font attribute to the string instead did work. – Sheepdogsheep Jun 26 '14 at 09:03
  • 12
    Guys, don't forget about the Apple statement: __In iOS 7 and later, 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.__ – SoftDesigner Jul 01 '14 at 13:22
  • 2
    ceil wasn't enough for me, but found that using ceil and also adding 0.5 did the trick – dwery Jan 29 '15 at 17:41
15

Here is my working code snippet:

NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:attributeDict];

NSString *headline  = [dict objectForKey:@"title"];  
UIFont *font        = [UIFont boldSystemFontOfSize:18];  
CGRect  rect        = [headline boundingRectWithSize:CGSizeMake(300, 1000) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:font} context:nil];

CGFloat height      = roundf(rect.size.height +4)

I added 4px to the calculated height, because without these 4px, there is one line missing.

I use this code snippet in a tableView and add the "height" to an array of NSNumbers and I get the correct cell height for the default textLabel.

Add 4 more pixel if you want more space under the text in the textLabel.

**** UPDATE ****

I do not agree with the "width bug of 40px", I shout be the 4px of missing height, because 4px is the default height of a space between a letter and the bound of a single line. You can check it with a UILabel, for a fontsize of 16 you need a UILabel height of 20.

But if your last line has no "g" or whatever in it, the measuring could be miss the 4px of height.

I rechecked it with a little method, I get an accurate height of 20,40 or 60 for my label and a right width less than 300px.

To support iOS6 and iOS7, you can use my method:

- (CGFloat)heightFromString:(NSString*)text withFont:(UIFont*)font constraintToWidth:(CGFloat)width
{
    CGRect rect;

    float iosVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
    if (iosVersion >= 7.0) {
        rect = [text boundingRectWithSize:CGSizeMake(width, 1000) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:font} context:nil];
    }
    else {
        CGSize size = [text sizeWithFont:font constrainedToSize:CGSizeMake(width, 1000) lineBreakMode:NSLineBreakByWordWrapping];
        rect = CGRectMake(0, 0, size.width, size.height);
    }
    NSLog(@"%@: W: %.f, H: %.f", self, rect.size.width, rect.size.height);
    return rect.size.height;
}

**** UPGRADE ****

Thanks to your comments, I upgraded my function as followed. Since sizeWithFont is deprecated and you will get a warning in XCode, I added the diagnostic-pragma-code to remove the warning for this particular function-call/block of code.

- (CGFloat)heightFromStringWithFont:(UIFont*)font constraintToWidth:(CGFloat)width
{
    CGRect rect;

    if ([self respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)]) {
        rect = [self boundingRectWithSize:CGSizeMake(width, 1000) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:font} context:nil];
    }
    else {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
        CGSize size = [self sizeWithFont:font constrainedToSize:CGSizeMake(width, 1000) lineBreakMode:NSLineBreakByWordWrapping];
        rect = CGRectMake(0, 0, size.width, size.height);
#pragma GCC diagnostic pop
    }
    return ceil(rect.size.height);
}

In addition to the 4px topic: depending which font and font-weight you use, the calculation returns different height-values. In my case: HelveticaNeue-Medium with a fontsize of 16.0 returns a line-height of 20.0 for a single line but 39.0 for two lines, 78px for 4 lines --> 1px missing for every line - beginning with line 2 - but you want to have your fontsize + 4px linespace for every line you have to get a height-result.
Please keep that in mind while coding!
I don´t have a function yet for this "problem" but I will update this post when I´m finished.

Rikco
  • 376
  • 5
  • 9
  • 1
    You should probably be using [text respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)] rather than checking a float value. – Samah Nov 03 '14 at 04:06
  • 1
    It's better to use ceil function instead of +4pt, look at this answer http://stackoverflow.com/a/23563152/667483 – surfrider Feb 12 '15 at 06:48
2

If I understand correctly, you are using boundingRectWithSize: just as a way of getting the size you would get with sizeWithFont (meaning you want directly the CGSize, not the CGRect)?

This looks like what you are looking for :

Replacement for deprecated sizeWithFont: in iOS 7?

They are using sizeWithAttributes: to get the size, as a replacement for sizeWithFont.

Do you still get the wrong size using something like this :

UIFont *fontText = [UIFont fontWithName:[AppHandlers zHandler].fontName size:16];
                    // you can use your font.

expectedLabelSize = [myString sizeWithAttributes:@{NSFontAttributeName:fontText}];
Community
  • 1
  • 1
vinaut
  • 2,416
  • 15
  • 13
  • but how can i use CGSize maximumLabelSize = CGSizeMake(310, 9999)? I need correct height and width. – Nirav Jain Oct 19 '13 at 08:54
  • 1
    Is there any attributes that tells sizeWithAttributes: to constraint its width/height? – Nirav Jain Oct 19 '13 at 09:12
  • Sorry, but I don't get what your problem is. You want to size the label with the font size, but not more than a maximum height, if I understand correctly. You say that you are able to do that with sizeWithFont, but you want an alternative now that this method is deprecated, correct ? You should be able to plug in sizeWithAttribues: in the same way you were using sizeWithFont: . How were you constraining the label size when you were using sizeWithFont ? Can you post the code that was working for you using sizeWithFont ? – vinaut Oct 19 '13 at 09:29
  • 2
    He was using sizeWithFont:constrainedToSize:lineBreakMode: and there is no way to pass constrainedToSize value to sizeWithAttributes. – zh. Jan 09 '14 at 16:40
2

The @SoftDesigner's comment has worked for me

CGRect descriptionRect = [description boundingRectWithSize:CGSizeMake(width, 0)
                                                       options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                                    attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:12]}
                                                       context:nil];
result = ceil(descriptionRect.size.height);
Myrddin
  • 81
  • 4
1

for finding size of label run time sizewithfont is deprecated for iOS 7.0 instead of that you have to use -boundingRectWithSize:options:attributes:context: method

you can use it like below code

CGSize constraint = CGSizeMake(MAXIMUM_WIDHT, TEMP_HEIGHT);
NSRange range = NSMakeRange(0, [[self.message body] length]);

NSDictionary *attributes = [YOUR_LABEL.attributedText attributesAtIndex:0 effectiveRange:&range];
CGSize boundingBox = [myString boundingRectWithSize:constraint options:NSStringDrawingUsesFontLeading attributes:attributes context:nil].size;
int numberOfLine = ceil((boundingBox.width) / YOUR_LABEL.frame.size.width);
CGSize descSize = CGSizeMake(ceil(boundingBox.width), ceil(self.lblMessageDetail.frame.size.height*numberOfLine));

CGRect frame=YOUR_LABEL.frame;
frame.size.height=descSize.height;
YOUR_LABEL.frame=frame;

here you have to give width to maximum length for finding height or width.

try this it is working for me.

Pratik
  • 2,399
  • 17
  • 36