134

How do you return a multiline text CGSize from the new iOS 7 method sizeWithAttributes?

I would like this to produce the same results as sizeWithFont:constrainedToSize.

NSString *text = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus eu urna quis lacus imperdiet scelerisque a nec neque. Mauris eget feugiat augue, vitae porttitor mi. Curabitur vitae sollicitudin augue. Donec id sapien eros. Proin consequat tellus in vehicula sagittis. Morbi sed felis a nibh hendrerit hendrerit. Lorem ipsum dolor sit."

CGSize textSize = [text sizeWithAttributes:@{ NSFontAttributeName : [UIFont fontWithName:@"HelveticaNeue-Light" size:16.0] }];

This method only produces the height for a single line of text.

Wayne Chen
  • 305
  • 2
  • 15
morcutt
  • 3,739
  • 8
  • 30
  • 47
  • Have a look at this: http://stackoverflow.com/questions/18673176/sizewithfontconstrainedtosizelinebreakmode-deprecated/19137272?noredirect=1#19137272 –  Oct 02 '13 at 19:20
  • 6
    +1 for having the same font as me :) – Lescai Ionel Jan 13 '14 at 14:54

9 Answers9

297

well you can try this :

NSDictionary *attributes = @{NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue" size:14]};
// NSString class method: boundingRectWithSize:options:attributes:context is
// available only on ios7.0 sdk.
CGRect rect = [textToMeasure boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX)
                                          options:NSStringDrawingUsesLineFragmentOrigin
                                       attributes:attributes
                                          context:nil];
oiledCode
  • 8,589
  • 6
  • 43
  • 59
  • 4
    For the first time i see this notation for dictionaries `@{...}`. What is it called? – Martin Berger Oct 22 '13 at 14:50
  • Any way to specify max number of lines? – jonasonline Jan 22 '14 at 19:57
  • 4
    Bro, i was almost losing my faith in SO, then i came here. – NSPunk Apr 11 '14 at 06:34
  • 21
    Wow. So much more obtuse than the original `sizeWithFont:constrainedToSize:` method that was deprecated. Apple must really hate us. In any case, +1. – aroth Jun 07 '14 at 14:50
  • 1
    Why do you use `MAXFLOAT` instead of `CGFLOAT_MAX`? – Julian F. Weinert Jul 02 '14 at 13:37
  • 1
    Actually I wrote this code quickly to answer the question.. Thanks for pointing this out the correct constant to use is CGFLOAT_MAX, edited the answer – oiledCode Jul 02 '14 at 13:59
  • 19
    Swift version: ```var size = textToMeasure.boundingRectWithSize( CGSizeMake(width, CGFloat.max), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes:attrs, context:nil).size``` – mdziadkowiec Apr 14 '15 at 13:04
  • 1
    its not working with New Line Character my string is like @"Hello this is new \n Label testing" – Tarun Seera Feb 25 '16 at 13:45
  • @iOSRocks have a look at this http://stackoverflow.com/questions/20602491/boundingrectwithsize-does-not-respect-word-wrapping – oiledCode Feb 25 '16 at 14:32
  • If getting a 'extra argument attributes' error in Swift version make sure that the boundingRectWithSize is performed on self.textLabel.attributedText.string rather than self.textLabel.attributedText - I just spent ages trying to get my head round that oversight – RobertyBob Jul 16 '16 at 12:45
  • This is always returning the size for a string, regardless of the font size I give it. Why could that be happening? (I'm on OS X, not iOS) – Addison Jul 28 '16 at 15:50
  • where does width come from, is it a value already calculated or do i need to have another `CGFloat width = 0.0;` outside of this function since i will be using the width later from the struct, hence my minor confusion. thank you! – Jon Weinraub Apr 27 '20 at 22:29
23

This is how I did it:

    // Get a font to draw it in
UIFont *font = [UIFont boldSystemFontOfSize: 28];

CGRect textRect;
NSDictionary *attributes = @{NSFontAttributeName: font};

// How big is this string when drawn in this font?
textRect.size = [text sizeWithAttributes:attributes];

// Draw the string
[text drawInRect:textRect withAttributes:attributes];
Gnawbone
  • 339
  • 2
  • 3
4

Here's my method to deal with both situations, goes in an NSString category.

- (CGSize) sizeWithFontOrAttributes:(UIFont *) font {
    if (IS_IOS7) {
        NSDictionary *fontWithAttributes = @{NSFontAttributeName:font};
        return [self sizeWithAttributes:fontWithAttributes];
    } else {
        return [self sizeWithFont:font];
    }
}
Dan Rosenstark
  • 68,471
  • 58
  • 283
  • 421
3

For Xamarin.iOS:

UIFont descriptionLabelFont =  UIFont.SystemFontOfSize (11);
NSString textToMeasure = (NSString)DescriptionLabel.Text;

CGRect labelRect = textToMeasure.GetBoundingRect (
    new CGSize(this.Frame.Width, nfloat.MaxValue), 
    NSStringDrawingOptions.UsesLineFragmentOrigin, 
    new UIStringAttributes () { Font = descriptionLabelFont }, 
    new NSStringDrawingContext ()
);
testing
  • 19,681
  • 50
  • 236
  • 417
3

Swift 2.3:

let attributes = [NSFontAttributeName:UIFont(name: "HelveticaNeue", size: 14)]
let rect = NSString(string: textToMeasure).boundingRectWithSize(
        CGSizeMake(width, CGFLOAT_MAX), 
        options: NSStringDrawingOptions.UsesLineFragmentOrigin, 
        attributes: attributes, context: nil)

Swift 4:

let attributes = [NSFontAttributeName:UIFont(name: "HelveticaNeue", size: 14)]
let rect = NSString(string: textToMeasure).boundingRect(
                    with: CGSize(width: width, height: CGFloat.greatestFiniteMagnitude),
                    options: NSStringDrawingOptions.usesLineFragmentOrigin,
                    attributes: attributes as [NSAttributedString.Key : Any], context: nil)
MCG
  • 3
  • 2
Jelly
  • 4,522
  • 6
  • 26
  • 42
2

If you have the text, font, numberOfLines and width of your label set, this method returns the size of your label:

myLabel.numberOfLines = 0;

CGSize size = [myLabel sizeThatFits:CGSizeMake(myLabel.frame.size.width, CGFLOAT_MAX)];`
Marijn
  • 1,439
  • 12
  • 12
1

As an alternative, if you're looking at UITextView, you can always use the NSLayoutManager method:

CGSize textSize = [textView.layoutManager usedRectForTextContainer:textView.textContainer].size;

You can also find the line height for a given font by:

UIFont *font;
CGFloat lineHeight = font.lineHeight;
mikeho
  • 6,790
  • 3
  • 34
  • 46
0

[As a new user, I cannot post a comment to @testing's answer, but to make his answer (for xamarin.ios) more useful]

We can return a CGRect and only use the height parameter for the gui item we are targeting UIButton etc.Passing in any parameters we need as below

    public CGRect GetRectForString(String strMeasure, int fontSize, nfloat guiItemWidth)
    {
        UIFont descriptionLabelFont =  UIFont.SystemFontOfSize (fontSize);
        NSString textToMeasure = (NSString)strMeasure;

        CGRect labelRect = textToMeasure.GetBoundingRect (
            new CGSize(guiItemWidth, nfloat.MaxValue), 
            NSStringDrawingOptions.UsesLineFragmentOrigin, 
            new UIStringAttributes () { Font = descriptionLabelFont }, 
            new NSStringDrawingContext ()
        );

        return labelRect;
    }

        header_Revision.Frame = new CGRect (5
                                            , verticalAdjust
                                            , View.Frame.Width-10
                                            , GetRectForString( header_Revision.Title(UIControlState.Normal)
                                                              , 18
                                                              , View.Frame.Width-10 ).Height
                                            );
Stuart Siegler
  • 1,686
  • 4
  • 30
  • 38
Matt
  • 1
  • This was actually supposed to be under testing's nice code for Xamarin.IOS :) Hope it helps anyone :) – Matt Jun 18 '15 at 12:21
  • When you have more rep, a comment like this would typically be appended to the post. You cant do that yet, so thanks for additional data, and welcome to Stack Overflow. – Stuart Siegler Jun 18 '15 at 12:46
0
CGSize stringsize = [lbl.text sizeWithAttributes:
                         @{NSFontAttributeName:[UIFont fontWithName:FontProximaNovaRegular size:12.0]}];


CGSize adjustedSize = CGSizeMake(ceilf(stringsize.width), ceilf(stringsize.height));

use ceilf method to manage properlly

jenish
  • 268
  • 3
  • 11