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."
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.
sizeWithFont
internally truncates the string before calculating the size. – Makeshift