Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scaling text to fit on iPhone

I'm having a bit of trouble working out the "best" way to render text in my application.

My main view consists of a text view, and the design of the application dictates a few things:

  • The (font) size of the text should be dynamic
  • The text frame should be centred vertically in the view
  • Hyphenation should be automatic and only when needed (avoided if possible)

At the moment i'm using a UILabel and the following code to try and guess the best font size to use for the amount of text:

txt  = @"this is just some sample text";

mylabel.font = [self getFontForString:txt];
mylabel.adjustsFontSizeToFitWidth = YES;
mylabel.numberOfLines = 0;
[mylabel setText:txt];

And:

- (UIFont *) getFontForString:(NSString *)txt {
     CGFloat                textLength = txt.length;
     CGFloat                maxFontSize = 71;
     CGFloat                minFontSize = 27;
     CGFloat                newFontSize = 0;

     NSArray                *chunks = [txt componentsSeparatedByString:@" "];
     NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"length" ascending:NO] autorelease];
     NSArray                *sortedChunks = [chunks sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];

     CGSize                labelSize = theThingLabel.bounds.size;
     CGSize                projectedSize = [[sortedChunks objectAtIndex:0] sizeWithFont:[UIFont boldSystemFontOfSize:maxFontSize]];

     if (projectedSize.width > labelSize.width) {
          CGFloat percentageDifference = ((projectedSize.width - labelSize.width)/labelSize.width)*100;
          if (percentageDifference > 50) {
               newFontSize = ((minFontSize/percentageDifference)*100) - 10;
               if (newFontSize < minFontSize) newFontSize = minFontSize;
          } else {
               newFontSize = ((percentageDifference/maxFontSize)*100) - 10;
               if(newFontSize < (maxFontSize/2)) newFontSize = maxFontSize - abs(newFontSize);
          }
     } else {
          if ( textLength > 11 && textLength < 255) {
               newFontSize = (maxFontSize - ((maxFontSize - minFontSize) * ((textLength- 11) / 100)));
          } else if (textLength <= 11) {
               newFontSize = maxFontSize;
          } else if (textLength >= 255) {
               newFontSize = minFontSize;
          }
     }

     return [UIFont boldSystemFontOfSize:newFontSize];
}

This works, to an extent, but often falls over when the text is a bit on the long side, these two example show it rendering the following strings:

  • "short amount of text"
  • "a substantially longer amount of text which i still want to render nicely."

short textlonger text

As you can see in the second example (with far longer text) there are a number of issues:

  • The initial widow
  • The dropped y
  • The missing "nicely."

So with all this in mind, what are my options, I'm open to moving to using coretext if this is the right solution, but have no idea where to start, it's also possible I've made a mistake which I just can't see in my "font size guessing" code.

like image 297
craig t mackenzie Avatar asked Nov 16 '10 22:11

craig t mackenzie


People also ask

How do I resize my text screen?

Make text bigger on your screenTo go to the Ease of Access settings on your computer, press the Windows key+U. Under Make text bigger on the Display tab, drag the slider to the right to increase the size of the sample text. Once you're happy with the text size, select Apply. Windows scales up the size of all text.


1 Answers

The following method will be use full to get the font size for specific string for specific rectangle (area).

-(float) maxFontSizeThatFitsForString:(NSString*)_string inRect:(CGRect)rect withFont:(NSString *)fontName onDevice:(int)device {   
// this is the maximum size font that will fit on the device
float _fontSize = maxFontSize;
float widthTweak;

// how much to change the font each iteration. smaller
// numbers will come closer to an exact match at the 
// expense of increasing the number of iterations.
float fontDelta = 2.0;

// sometimes sizeWithFont will break up a word 
// if the tweak is not applied. also note that 
// this should probably take into account the
// font being used -- some fonts work better
// than others using sizeWithFont.
if(device == IPAD)
    widthTweak = 0.2;
else
    widthTweak = 0.2;

CGSize tallerSize = CGSizeMake(rect.size.width-(rect.size.width*widthTweak), 100000);
CGSize stringSize = CGSizeZero;

    if([[UIDevice currentDevice].systemVersion floatValue]>=7.0){
        NSDictionary *stringAttributes = [NSDictionary dictionaryWithObject:[UIFont boldSystemFontOfSize:17] forKey: NSFontAttributeName];
        stringSize = [_string boundingRectWithSize: tallerSize options:NSStringDrawingUsesLineFragmentOrigin attributes:stringAttributes context:nil].size;
    }
    else{
        stringSize = [_string sizeWithFont:[UIFont fontWithName:fontName size:_fontSize] constrainedToSize:tallerSize];
    }

while (stringSize.height >= rect.size.height)
{       
    _fontSize -= fontDelta;
    stringSize = [_string sizeWithFont:[UIFont fontWithName:fontName size:_fontSize] constrainedToSize:tallerSize];
}

return _fontSize;
}

Use this and get the font size and assign to the label.

like image 100
Satya Avatar answered Sep 22 '22 23:09

Satya