Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiline UILabel with adjustsFontSizeToFitWidth

I have a multiline UILabel whose font size I'd like to adjust depending on the text length. The whole text should fit into the label's frame without truncating it.

Unfortunately, according to the documentation the adjustsFontSizeToFitWidth property "is effective only when the numberOfLines property is set to 1".

I tried to determine the adjusted font size using

-[NSString (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode] 

and then decrementing the font size until it fits. Unfortunately, this method internally truncates the text to fit into the specified size and returns the size of the resulting truncated string.

like image 439
Ortwin Gentz Avatar asked Dec 08 '10 00:12

Ortwin Gentz


2 Answers

In this question, 0x90 provides a solution that - although a bit ugly - does what I want. Specifically, it deals correctly with the situation that a single word does not fit the width at the initial font size. I've slightly modified the code so that it works as a category on NSString:

- (CGFloat)fontSizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size {     CGFloat fontSize = [font pointSize];     CGFloat height = [self sizeWithFont:font constrainedToSize:CGSizeMake(size.width,FLT_MAX) lineBreakMode:UILineBreakModeWordWrap].height;     UIFont *newFont = font;      //Reduce font size while too large, break if no height (empty string)     while (height > size.height && height != 0) {            fontSize--;           newFont = [UIFont fontWithName:font.fontName size:fontSize];            height = [self sizeWithFont:newFont constrainedToSize:CGSizeMake(size.width,FLT_MAX) lineBreakMode:UILineBreakModeWordWrap].height;     };      // Loop through words in string and resize to fit     for (NSString *word in [self componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]) {         CGFloat width = [word sizeWithFont:newFont].width;         while (width > size.width && width != 0) {             fontSize--;             newFont = [UIFont fontWithName:font.fontName size:fontSize];                width = [word sizeWithFont:newFont].width;         }     }     return fontSize; } 

To use it with a UILabel:

    CGFloat fontSize = [label.text fontSizeWithFont:[UIFont boldSystemFontOfSize:15] constrainedToSize:label.frame.size];     label.font = [UIFont boldSystemFontOfSize:fontSize]; 

EDIT: Fixed the code to initialize newFont with font. Fixes a crash under certain circumstances.

like image 164
Ortwin Gentz Avatar answered Sep 21 '22 22:09

Ortwin Gentz


In some cases, changing "Line Breaks" from "Word Wrap" to "Truncate Tail" may be all you need, if you know how many lines you want (e.g. "2"): Credit: Becky Hansmeyer

like image 35
weienw Avatar answered Sep 23 '22 22:09

weienw