Replacement for deprecated -sizeWithFont:constrainedToSize:lineBreakMode: in iOS 7?

73,141

Solution 1

You could try this:

CGRect textRect = [text boundingRectWithSize:size
                                 options:NSStringDrawingUsesLineFragmentOrigin
                              attributes:@{NSFontAttributeName:FONT}
                                 context:nil];

CGSize size = textRect.size;

Just change "FONT" for an "[UIFont font....]"

Solution 2

As we cant use sizeWithAttributes for all iOS greater than 4.3 we have to write conditional code for 7.0 and previous iOS.

1) Solution 1:

if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")) {
   CGSize size = CGSizeMake(230,9999);
   CGRect textRect = [specialityObj.name  
       boundingRectWithSize:size
                    options:NSStringDrawingUsesLineFragmentOrigin
                 attributes:@{NSFontAttributeName:[UIFont fontWithName:[AppHandlers zHandler].fontName size:14]}
                    context:nil];
   total_height = total_height + textRect.size.height;   
}
else {
   CGSize maximumLabelSize = CGSizeMake(230,9999); 
   expectedLabelSize = [specialityObj.name sizeWithFont:[UIFont fontWithName:[AppHandlers zHandler].fontName size:14] constrainedToSize:maximumLabelSize lineBreakMode:UILineBreakModeWordWrap]; //iOS 6 and previous. 
   total_height = total_height + expectedLabelSize.height;
}

2) Solution 2

UILabel *gettingSizeLabel = [[UILabel alloc] init];
gettingSizeLabel.font = [UIFont fontWithName:[AppHandlers zHandler].fontName size:16]; // Your Font-style whatever you want to use.
gettingSizeLabel.text = @"YOUR TEXT HERE";
gettingSizeLabel.numberOfLines = 0;
CGSize maximumLabelSize = CGSizeMake(310, 9999); // this width will be as per your requirement

CGSize expectedSize = [gettingSizeLabel sizeThatFits:maximumLabelSize];

The first solution is sometime fail to return proper value of height. so use another solution. which will work perfectly.

The second option is quite well and working smoothly in all iOS without conditional code.

Solution 3

Here is simple solution :

Requirements :

CGSize maximumSize = CGSizeMake(widthHere, MAXFLOAT);
UIFont *font = [UIFont systemFontOfSize:sizeHere];

Now As constrainedToSizeusage:lineBreakMode: usage is deprecated in iOS 7.0:

CGSize expectedSize = [stringHere sizeWithFont:font constrainedToSize:maximumSize lineBreakMode:NSLineBreakByWordWrapping];

Now usage in greater version of iOS 7.0 will be:

// Let's make an NSAttributedString first
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:stringHere];
//Add LineBreakMode
NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
[paragraphStyle setLineBreakMode:NSLineBreakByWordWrapping];
[attributedString setAttributes:@{NSParagraphStyleAttributeName:paragraphStyle} range:NSMakeRange(0, attributedString.length)];
// Add Font
[attributedString setAttributes:@{NSFontAttributeName:font} range:NSMakeRange(0, attributedString.length)];

//Now let's make the Bounding Rect
CGSize expectedSize = [attributedString boundingRectWithSize:maximumSize options:NSStringDrawingUsesLineFragmentOrigin context:nil].size;

Solution 4

Below are two simple methods that will replace these two deprecated methods.

And here are the relevant references:

If you are using NSLineBreakByWordWrapping, you don't need to specify the NSParagraphStyle, as that is the default: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSParagraphStyle_Class/index.html#//apple_ref/occ/clm/NSParagraphStyle/defaultParagraphStyle

You must get the ceil of the size, to match the deprecated methods' results. https://developer.apple.com/library/ios/documentation/UIKit/Reference/NSString_UIKit_Additions/#//apple_ref/occ/instm/NSString/boundingRectWithSize:options:attributes:context:

+ (CGSize)text:(NSString*)text sizeWithFont:(UIFont*)font {    
    CGSize size = [text sizeWithAttributes:@{NSFontAttributeName: font}];
    return CGSizeMake(ceilf(size.width), ceilf(size.height));
}

+ (CGSize)text:(NSString*)text sizeWithFont:(UIFont*)font constrainedToSize:(CGSize)size{
    CGRect textRect = [text boundingRectWithSize:size
                                     options:NSStringDrawingUsesLineFragmentOrigin
                                  attributes:@{NSFontAttributeName: font}
                                     context:nil];
    return CGSizeMake(ceilf(textRect.size.width), ceilf(textRect.size.height));
}

Solution 5

In most cases I used the method sizeWithFont:constrainedToSize:lineBreakMode: to estimate the minimum size for a UILabel to accomodate its text (especially when the label has to be placed inside a UITableViewCell)...

...If this is exactly your situation you can simpy use the method:

CGSize size = [myLabel textRectForBounds:myLabel.frame limitedToNumberOfLines:mylabel.numberOfLines].size;

Hope this might help.

Share:
73,141
user_Dennis_Mostajo
Author by

user_Dennis_Mostajo

Updated on July 19, 2020

Comments

  • user_Dennis_Mostajo
    user_Dennis_Mostajo almost 4 years

    In iOS 7, the method:

    - (CGSize)sizeWithFont:(UIFont *)font
         constrainedToSize:(CGSize)size
             lineBreakMode:(NSLineBreakMode)lineBreakMode 
    

    and the method:

    - (CGSize)sizeWithFont:(UIFont *)font
    

    are deprecated. How can I replace

    CGSize size = [string sizeWithFont:font
                     constrainedToSize:constrainSize
                         lineBreakMode:NSLineBreakByWordWrapping];
    

    and:

    CGSize size = [string sizeWithFont:font];
    
    • holex
      holex over 10 years
      the substitute method is -sizeWithAttributes:.
    • user_Dennis_Mostajo
      user_Dennis_Mostajo over 10 years
      ok holex thanks but, how can I use a font from label like a NSDIctionary? if my code is like: sizeWithFont:customlabel.font ;the void ask "sizeWithAttributes:<#(NSDictionary *)#>"
    • holex
      holex over 10 years
      here is the official documentation of how you can define attributes: developer.apple.com/library/ios/documentation/UIKit/Referenc‌​e/…
  • Barlow Tucker
    Barlow Tucker over 10 years
    Apple's documentation says that you should not call this method directly.
  • user4951
    user4951 over 10 years
    why 230, 999? Where do you get the number>
  • user4951
    user4951 over 10 years
    And where do you mention NSLineBreakByWordWrapping? Wherre did it go?
  • Florian Friedrich
    Florian Friedrich over 10 years
    NSLineBreakByWordWrapping would go within a NSParagraphStyle. So for example: NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping; In the attributes you would then need to add NSParagraphStyleAttributeName: paragraphStyle.copy...
  • Florian Friedrich
    Florian Friedrich over 10 years
    The 230 can be any number. It represents the width you want for your label. The 9999 I'd rather replace with INFINITY or MAXFLOAT.
  • Rivera
    Rivera over 10 years
    Not mentioned in iOS 7 SDK documentation at least.
  • manicaesar
    manicaesar over 10 years
    @ffried in my case adding the paragraphStyle with line break other than NSLineBreakByWordWrapping caused size to be calculated for just one line… Any thoughts?
  • Florian Friedrich
    Florian Friedrich over 10 years
    @manicaesar Except for NSLineBreakByWordWrapping and NSLineBreakByCharWrapping all line break modes are made for only one line (by truncating the string). I've just tested it and all line break modes work as expected.
  • Florian Friedrich
    Florian Friedrich over 10 years
    Don't forget that boundingRectWithSize:options:attributes:context: returns fractional values. You need to do ceil(textRect.size.height) and ceil(textRect.size.width) respectively to get the real height/width.
  • manicaesar
    manicaesar over 10 years
    Hmm, you are right, having (for example) NSLineBreakModeByTruncatingMiddle makes no sense for multiple lines. If someone want to have last line with tail truncated, he can use NSStringDrawingTruncatesLastVisibleLine. Thanks!
  • Javal Nanda
    Javal Nanda about 10 years
    Does this return exact size same as sizeWithFont ? I am facing this issue and using the above method still has a height difference of 3 to 4 pixels which causes lot of difference in UI for iOS 6.0 and iOS 7.0 when compared side by side
  • Nirav Jain
    Nirav Jain about 10 years
    boundingRectWithSize is not returning correct width and height.
  • Jim
    Jim about 10 years
    Second solution is working like a charm. Thanks Nirav.
  • Dimple
    Dimple about 10 years
    "[AppHandlers zHandler]" gives an error.. "Undeclared Identifiers". How to solve that?
  • JRam13
    JRam13 almost 10 years
    What the heck is BOLIVIASize?
  • Nirav Jain
    Nirav Jain almost 10 years
    boundingRectWithSize is still returning wrong output as i test it. The scenario is when you are testing for long and multiple paragraphs.
  • Sawsan
    Sawsan almost 10 years
    @Nirav I faced the same problem for long paragraph, but after investigating the problem I found that I provide not accurate attributes like the font size. It was 12 and it should be 14 as in the interface builder in my case
  • Ramaraj T
    Ramaraj T almost 10 years
    Welcome to StackOverFlow. Do not post a same answer again. If you need to add something to an answer, make a comment or do an edit to the answer.
  • user3575114
    user3575114 almost 10 years
    ok..I will take that into consideration next time.Thank you for your advice.
  • Marius Soutier
    Marius Soutier over 9 years
    NSLineBreakByWordWrapping is represented by NSStringDrawingUsesLineFragmentOrigin.