Custom Fonts on the iPad and iOS 4

In the old days (you know, before the iPad and iOS 4), text layout in iOS was not for the faint of heart. A developer who wanted more than UILabel could provide was forced to manually layout and draw text with Quartz. Those days are gone now thanks to Core Text and it sibling CATextLayer.

Core Text could fill an entire book on its own. Luckily, most of Core Text is only necessary for about 5% of iOS apps. Most of us do not need to layout large amounts of text with complex style attributes. Sometimes we just want to use our own custom font or italicize one word in a label. There is a solution for the rest of us: CATextLayer. Like its counterparts in the Core Animation framework, CATextLayer allows us to take advantage of a complex API (Core Text in this case) without much effort.

We will cover a simple use of CATextLayer this time: displaying a custom font. As always, I have added more code to my CA360 project. Check it out on github to follow along.

Displaying Custom Fonts

Using CATextLayer to display a custom font is fairly simple. There are two things we must do to make it work:

  • Load the font into memory (most likely from our app bundle).
  • Hand the font to our CATextLayer for drawing.

Once the font has been passed to our CATextLayer instance, we can set the string of the layer and treat it like any other Core Animation layer. Let’s see how this looks in code.

Load the Font into Memory

Because CATextLayer uses Core Text internally, we’ll need to touch a little of Core Text to render our custom font. Like Quartz, Core Text is a Core Foundation API, and it is entirely C based. If you’ve done any custom drawing with Quartz, the Core Text API will look familiar. If this is your first foray into a Core Foundation framework, don’t worry, CATextLayer abstracts most of Core Text away. You still might want to take a look at the Apple Core Foundation docs if this part is way over your head.

CATextLayer expects a CTFontRef (CT is the prefix for all Core Text types and functions) for its font attribute. This is where we have to use Core Text directly.

We actually go about this in a bit of a roundabout way. Core Text does not know how to load a font from a font file. That’s the domain of Qaurtz. So we have to load the font file with Quartz and convert the CGFontRef to a CTFontRef. Thankfully, this conversion is just a single function call.

- (CTFontRef)newCustomFontWithName:(NSString *)fontName
                            ofType:(NSString *)type
                        attributes:(NSDictionary *)attributes
  NSString *fontPath = [[NSBundle mainBundle] pathForResource:fontName ofType:type];

  NSData *data = [[NSData alloc] initWithContentsOfFile:fontPath];
  CGDataProviderRef fontProvider = CGDataProviderCreateWithCFData((CFDataRef)data);
  [data release];

  CGFontRef cgFont = CGFontCreateWithDataProvider(fontProvider);

  CTFontDescriptorRef fontDescriptor = CTFontDescriptorCreateWithAttributes((CFDictionaryRef)attributes);
  CTFontRef font = CTFontCreateWithGraphicsFont(cgFont, 0, NULL, fontDescriptor);
  return font;

As you can see, we use a CGDataProvider to load the font from the app bundle and create a CGFontRef with the data provider.

Next, we create at CTFontDescriptorRef. CTFont is very configurable, and the CTFontDescriptor holds all of that configuration information. We’ll get to it in a later post. You can ignore the CTFontDescriptor for now.

The last thing we do in this method is create the CTFontRef using our CGFontRef and the CTFontDescriptorRef. Now, our font is loaded and ready to be used.

Configure the CATextLayer

CATextLayer could not be easier to configure. Like other CALayer objects, the CATextLayer exposes a set of attributes that we can set to configure the look of our text. Since we loaded the font earlier, we can just set the font attribute of CATextLayer, and the layer handles the rest.

normalTextLayer_ = [[CATextLayer alloc] init];
normalTextLayer_.font = font;
normalTextLayer_.string = @"This is just a plain old CATextLayer";
normalTextLayer_.wrapped = YES;
normalTextLayer_.foregroundColor = [[UIColor purpleColor] CGColor];
normalTextLayer_.fontSize = 20.f;
normalTextLayer_.alignmentMode = kCAAlignmentCenter;
normalTextLayer_.frame = CGRectMake(0.f, 10.f, 320.f, 32.f);

As you can see, there are a bunch of configuration options for CATextLayer. You can see them all in the class reference doc. Once we’ve finished setting up our layer, we add it to the layer tree, and Core Animation will render it. The final product looks something like this:

Now, Unleash the Designers

Thanks to the updates in iOS 4, developers are no longer stuck with the fonts built into iOS. Good typography can really elevate the look of an app, and I encourage you to experiment with quality fonts. Let you designers run wild. They’ll love you for it.

19 Responses to “Custom Fonts on the iPad and iOS 4”