31

A "quicky": how can I get the size (width) of a NSString?

I'm trying to see if the string width of a string to see if it is bigger than a given width of screen, case in which I have to "crop" it and append it with "...", getting the usual behavior of a UILabel. string.length won't do the trick since AAAAAAAA and iiiiii have the same length but different sizes (for example).

I'm kind of stuck.

Thanks a lot.

camilo
  • 1,451
  • 3
  • 20
  • 31
  • While not a complete answer... I think most iOS and MacOS text-field renderers have this mode of "truncation" that add the ellipsis (...) where text is truncated --- automatically. The whole need to do this on your own then disappears. – Motti Shneor Jul 26 '21 at 17:53

5 Answers5

38

This is a different approach. Find out the minimum size of the text so that it won't wrap to more than one line. If it wraps to over one line, you can find out using the height.

You can use this code:

CGSize maximumSize = CGSizeMake(300, 9999);
NSString *myString = @"This is a long string which wraps";
UIFont *myFont = [UIFont fontWithName:@"Helvetica" size:14];
CGSize myStringSize = [myString sizeWithFont:myFont 
                           constrainedToSize:maximumSize 
                               lineBreakMode:self.myLabel.lineBreakMode];

300 is the width of the screen with a little space for margins. You should substitute your own values for font and size, and for the lineBreakMode if you're not using IB.

Now myStringSize will contain a height which you can check against the height of something you know is only 1 line high (using the same font and size). If it's bigger, you'll need to cut the text. Note that you should add a ... to the string before you check it again (adding the ... might push it over the limit again).

Put this code in a loop to cut the text, then check again for the correct height.

WrightsCS
  • 50,551
  • 22
  • 134
  • 186
nevan king
  • 112,709
  • 45
  • 203
  • 241
  • Thanks a lot! Your answer was correct, and the trick to append the "..." before checking the size again was wise. – camilo Apr 19 '10 at 17:12
  • 5
    For iOS 7 you should check out [this answer](http://stackoverflow.com/a/18951386/3965) – Mr Rogers Dec 26 '13 at 21:09
  • This does not work. `NSString.StringSize(UIFont font, nfloat forWidth, UILineBreakMode breakMode)` is a defective method that always returns the height of a single line, even when using `UILineBreakMode.WordWrap` and passing in a string that should be wrapping to many lines for the width given. Does anyone know why this is? Or can anyone provide a better solution? – Perrin Larson Sep 09 '17 at 21:08
15

Use below method.

Objective-C

- (CGSize)findHeightForText:(NSString *)text havingWidth:(CGFloat)widthValue andFont:(UIFont *)font {
    CGSize size = CGSizeZero;
    if (text) {
        CGRect frame = [text boundingRectWithSize:CGSizeMake(widthValue, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{ NSFontAttributeName:font } context:nil];
        size = CGSizeMake(frame.size.width, frame.size.height + 1);
    }
    return size;
}

Swift 3.0

func findHeight(forText text: String, havingWidth widthValue: CGFloat, andFont font: UIFont) -> CGSize {
    var size = CGSizeZero
    if text {
        var frame = text.boundingRect(withSize: CGSize(width: widthValue, height: CGFLOAT_MAX), options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)
        size = CGSize(width: frame.size.width, height: frame.size.height + 1)
    }
    return size
}
Himanshu padia
  • 7,428
  • 1
  • 47
  • 45
  • Why height + 1? – DawnSong Sep 27 '16 at 08:42
  • `size = CGSize(width: ceilf(frame.width), height: ceilf(frame.height))` is better. – DawnSong Sep 27 '16 at 08:51
  • The question is asking how to get the width of the string. This answer is how to get the height of the string if you already know its width... good information but not an answer to the question. I think a better approach to making this answer is to ask the right question and then answer it yourself, followed up with a possible comment to this question pointing you to the related question. – mah Feb 15 '18 at 16:04
4

You need to use Core Graphics to measure the string, as rendered in your specified font and size. See the answers to Measuring the pixel width of a string for a walkthrough.

Community
  • 1
  • 1
Jakob Borg
  • 23,685
  • 6
  • 47
  • 47
4
sizeWithFont:constrainedToSize:lineBreakMode 

is deprecated now. Use below code snippet,

UIFont *font=[UIFont fontWithName:@"Arial" size:16.f];

NSString *name = @"APPLE";

CGSize size = [name sizeWithAttributes:@{NSFontAttributeName:font}];
Gobi M
  • 3,243
  • 5
  • 32
  • 47
0

For whatever its worth --- I think the OP takes the wrong way to get there... if the measurement of width only serves to find the place where text should be clipped, and followed by ellipsis --- then OP should be aware of that this facility is implemented in all Text Views in Cocoa...

Pay attention to this enumeration:

typedef NS_ENUM(NSUInteger, NSLineBreakMode) {
    NSLineBreakByWordWrapping = 0,         // Wrap at word boundaries, default
    NSLineBreakByCharWrapping,        // Wrap at character boundaries
    NSLineBreakByClipping,        // Simply clip
    NSLineBreakByTruncatingHead,    // Truncate at head of line: "...wxyz"
    NSLineBreakByTruncatingTail,    // Truncate at tail of line: "abcd..."
    NSLineBreakByTruncatingMiddle    // Truncate middle of line:  "ab...yz"
} API_AVAILABLE(macos(10.0), ios(6.0), watchos(2.0), tvos(9.0));

By setting the line breaking mode of your text-field or text view to NSLineBreakByTruncatingTail, you'll achieve what you want, and probably at higher quality, without implementing yourself.

Motti Shneor
  • 2,095
  • 1
  • 18
  • 24