Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resizing UILabel to fit with Word Wrap

This is part of an iPhone application but should apply to Cocoa written in objC in general.

I have a UILabel holding various amounts of text (from single characters to several sentences). The text should always be displayed in the largest possible font that fits all the text within the UILabel. The maximum number of lines is set to 4 and the line break mode is set to word wrap.

Since multiple lines are used, adjustsFontSizeToFitWidth won't work for resizing the text.

Thus I am using a loop to determine the largest possible font size for each string as such:

    //Set the text  
    self.textLabel.text = text;
    //Largest size used  
    NSInteger fsize = 200;  textLabel.font = [UIFont
    fontWithName:@"Verdana-Bold"
    size:fsize];

    //Calculate size of the rendered string with the current parameters
    float height = [text sizeWithFont:textLabel.font
        constrainedToSize:CGSizeMake(textLabel.bounds.size.width,99999) 
        lineBreakMode:UILineBreakModeWordWrap].height;

    //Reduce font size by 5 while too large, break if no height (empty string)
    while (height > textLabel.bounds.size.height and height != 0) {   
        fsize -= 5;  
        textLabel.font = [UIFont fontWithName:@"Verdana-Bold" size:fsize];   
        height = [text sizeWithFont:textLabel.font 
            constrainedToSize:CGSizeMake(textLabel.bounds.size.width,99999) 
            lineBreakMode:UILineBreakModeWordWrap].height;
    };

This approach works well for the most part. The exception are long words. Let's take the string @"The experience foo." as an example. The word "experience", being much longer than the others will be split in half without being word-wrapped correctly and the string split across 4 lines. I am looking for a way to reduce the size further so that each individual word fits in one line.

Example:

-old-

Font size: 60

The
Exper
ience
foo

should be

-new-

Font size: 30

The
Experience
foo

There probably is an easy way to do this but I'm hitting a wall.

like image 259
0x90 Avatar asked Aug 19 '10 10:08

0x90


1 Answers

Here is the most elegant (yet somewhat hackish) way I found to make this work:

  1. Split the string into words
  2. Calculate the width of each word using the current font size
  3. Reduce the size of the string until each the word fits into one line

Resource consumption is low enough for this to work even in UITableViews full of strings edited this way.

Here is the new code:

//Set the text  
self.textLabel.text = text;
//Largest size used  
NSInteger fsize = 200;  textLabel.font = [UIFont fontWithName:@"Verdana-Bold"
                                                         size:fsize];

//Calculate size of the rendered string with the current parameters
float height = 
      [text sizeWithFont:textLabel.font
       constrainedToSize:CGSizeMake(textLabel.bounds.size.width,99999) 
           lineBreakMode:UILineBreakModeWordWrap].height;

//Reduce font size by 5 while too large, break if no height (empty string)
while (height > textLabel.bounds.size.height and height != 0) {   
    fsize -= 5;  
    textLabel.font = [UIFont fontWithName:@"Verdana-Bold" size:fsize];   
    height = [text sizeWithFont:textLabel.font 
              constrainedToSize:CGSizeMake(textLabel.bounds.size.width,99999) 
                  lineBreakMode:UILineBreakModeWordWrap].height;
};

// Loop through words in string and resize to fit
for (NSString *word in [text componentsSeparatedByString:@" "]) {
    float width = [word sizeWithFont:textLabel.font].width;
    while (width > textLabel.bounds.size.width and width != 0) {
        fsize -= 3;
        textLabel.font = [UIFont fontWithName:@"Verdana-Bold" size:fsize];
        width = [word sizeWithFont:textLabel.font].width;

    }
}
like image 178
0x90 Avatar answered Sep 21 '22 21:09

0x90