Ad

Our DNA is written in Swift
Jump

Understanding UIFont

Have you ever really TRULY looked at the documentation of UIFont?

I had to, because I was looking for some metrics information that I could use to custom draw UILabels. And if you want to be independent of what font is set, then you have to get certain metrics, but the Apple SDK documentation of UIFont leaves a bit to desire.

When I asked which characters would be good representatives of a font, I was sent a link to this blog “celebrating the beauty of the ampersand”. Fine, an ampersand will be there as well…

To visualize where each font metric belongs to I built assembled an app to show you what metric is which.

The font in the graphic is what you get by [UIFont boldSystemFontOfSize:56.0]. The Point Size is the only metric you have an influence over when you get a new font instance by means of any of the factory methods available. All the other values derive from this. I was most confused by the ascender and descender until I realized that ascender + 1 + descender is equal to the Point Size.

The baseline is the line on which all letters are standing. Leading is the measurement from one baseline to the next if you have text that is rendered on multiple lines. Finally you also get the height of captial letters and the height of the lowercase x. Why this is specifically singled out like this I cannot say, seems a bit unfair to have the small x represent all lowercase characters.

Helvetica is the font you generally get by the systemFont methods and rightfully so, Helvetica is a beautiful cut, so handsome in fact that it has it’s own movie. (Which is highly acclaimed BTW) It’s fine for use in most productivity apps and everything that wants to be compatible with the Apple look. But when you start using UILabels in games you will probably feel an urge to be somewhat more adventurous.

A more useful description

Being the seasoned Cocoa geek that we all are the first thing to try on any object is to see if it implements a useful description. Tuns out, UIFont does not. I tried to If you NSLog %@ the UIFont instance that is attached to a detailTextLabel of a subtitled tableViewCell. All you get is:

<UICFFont: 0x38898e0>

We can absolutely do better. Let’s add a category extension to UIFont.

UIFont+Description.h

#import 
 
@interface UIFont (Description)
 
@end

UIFont+Description.m

#import "UIFont+Description.h"
 
@implementation UIFont (Description)
 
- (NSString *)description
{
	return [NSString stringWithFormat:@"", self.fontName, self.pointSize];
}
 
@end

Note, that you don’t even need to add an import for this category to any class. Because EVERY descendant of NSObject has a description method this category extension actually overrules the existing one.

Ok, second try, again I want to know what font Apple is using for those subtitles:

cell.detailTextLabel.text = @"Some Text";
NSLog(@"%@", cell.detailTextLabel.font); // use our new description
}

We get a bit more info, but still there is a creepy feeling of Apple black magic, because for some strange reason the point size reported is 0, as if the font were undead, a floating spirit without a body.

<UICFFont: 'Helvetica-Bold', 0.00 point>

Clearly it displays, but how can this be without a size? Well, we instinctively tried theNSLog cellForRowAtIndexPath, but there is a better place to peak in the very last second before the tableview cell is displayed, in willDisplayCell. There we finally get the result we expect:

<UICFFont: 'Helvetica', 14.00 point>

That’s more like it.

All Fonts available on iPhone

The iPhone (currently) does not have any mechanisms (yet) to add custom fonts. This might or might not change (hint, hint) with the new SDK version that also supports the iPad. But for the time being and if you want to support all existing iDevices out there you have to be content with what font come preinstalled.

UIFonts are categorized in Font Family Names which group together different font cuts like oblique or bold. I made a tableview with all possible combinations, sorted by family name and rendered it into this bitmap for reference.

(In case you’re wondering how I did that: I adjusted the table view frame so that it is equal to the contentSize. Then I called the renderInContext of it’s layer into a bitmap context, which I made a UIImage of, which I saved as PNG. Then I re-saved this as GIF to reduce it from 516KB to 205KB.)

So you can see that there are 24 fonts available, some with variants. This gives us a bit of room to experiment with fonts different than the run-off-the-mill Helvetica.

You might have immediately noticed the LCD font and thought of using this as a digital clock. Trust me, everybody does, but you can forget about that right away. The designer of this font did not have fixed width digital readouts in mind when creating this font. The 1 is way smaller than other digits and therefore a label with this font tends to be jumping horizontally if the content changes. Stupid really, I’d like to ask him what he was thinking.

Some of the fonts appear to be having an awful lot of space below them. Look at the script font at the very end. This is also by design to have lots of space between multiple lines with this font. Also note that there really is no way to make custom variants like you know from MS Word. If there is no italic (aka oblique) variant of a font, then there is no way (currently) to make one.

Now to set a custom font you need you simply do something like this:

UIFont *detailFont = [UIFont fontWithName:@"Georgia-BoldItalic" size:21.0];

Now go ahead, be adventurous! Tell your customers that you now can do fonts as well. ANY font is possible (as long as it’s on this list) …

And iPad?

Half a year has passed since I wrote this article. Since the the iPad got released and with it a great deal more built-in fonts. Here’s a graphic that shows all of them.

Additionally you are able since iOS 3.2 to add your own fonts, but that’s a different story …


Categories: Recipes

19 Comments »

  1. Terrific post, Oliver. Thanks!

  2. Nice article, Oliver. One correction: it is a really bad idea to hardcode the class name in a description string. It would be better like this:

    – (NSString *)description {
    return [NSString stringWithFormat:@””, [self class], self, self.fontName, self.pointSize];
    }

  3. (at least if it weren’t for the fact that your comment engine has eaten all the format specifiers)

  4. Thanks, that is great to know. As always, great post.

  5. Hi Dr. Touch,

    Do you happen to have source available that was used to generate the top image here, the one with the cap height, x height, etc?

    My real goal is to reliably draw different fonts/sizes with the same baseline in an implementation of my own type of rich text without resorting to a web view. So basically I’m wondering if you have already solved this problem for this post.

    Also, thanks for the very useful info!

  6. I might have it somewhere. Need to go searching for it though.

  7. Bravo! Question: Some of those fonts have a lot of extra space on the bottom, causing them to be a bit north-of-center when using A-Za-z0-9 and so on. Are there any non-destructive tweaks that can be made to recenter those vs. manually offsetting things (ick, don’t want to go there)? I looked at UIFont (not much there), UILabel (better, but various experiments proved fruitless) … clues appreciated!

  8. On some of the ways of drawing you can shift the baseline with transforms.

  9. True, true. It becomes very specific to the font though. If only there was some way to automagically adjust it … (rummages around) … whoa! Check this out: https://github.com/kballard/FontLabel – will need to study s’more …

  10. Hi, would u mind sharing the source code? Thanks.

  11. Very interesting article, thanks a lot for the illustration, which is very helpful.

    That said, I think there is a small mistake in the article when you say : “I was most confused by the ascender and descender until I realized that ascender + 1 + descender is equal to the Point Size” It is not right for the illustration for example. I think that you meant that ascender + 1 + descender is equal to the Leading.