Seit iOS 3.2 lassen sich Apps mit eigenen Fonts ausstatten. Dummerweise kann man diese aber im InterfaceBuilder bis heute nicht für Labels, Buttons etc. verwenden. Manuell alle Labels im ViewController programmatisch zu ändern ist viel zu aufwändig. Leichter geht’s mit einer abgeleiteten Label-Klasse.

Vorbereitung

Die eigenen Fonts (im TrueType-Format .ttf) muss man zunächst in Xcode als Resource zum Projekt hinzufügen damit sie auch ins App-Bundle kopiert werden. Danach müssen die Dateinamen in die “App-Info.plist” unter den Schlüssel “UIAppFonts“ eingetragen werden. Für jeden Font eine eigenes Item in das Array.

Schließlich muss man noch herausbekommen, wie die Fonts eigentlich heißen — nicht die Dateien, sondern der Name, den “UIFont” erwartet. Mit einem kleinen Code-Schnipsel im “AppDelegate” geht das ganz leicht, wie z.B. auf Ajnaware’s Weblog gefunden:

// List all fonts on iPhone
NSArray *familyNames = [[NSArray alloc] initWithArray:[UIFont familyNames]];
NSArray *fontNames;
NSInteger indFamily, indFont;
for (indFamily=0; indFamily<[familyNames count]; ++indFamily)
{
    NSLog(@"Family name: %@", [familyNames objectAtIndex:indFamily]);
    fontNames = [[NSArray alloc] initWithArray:
        [UIFont fontNamesForFamilyName:
        [familyNames objectAtIndex:indFamily]]];
    for (indFont=0; indFont<[fontNames count]; ++indFont)
    {
        NSLog(@"    Font name: %@", [fontNames objectAtIndex:indFont]);
    }
    [fontNames release];
}
[familyNames release];

Ableitung

Jetzt kann man in Xcode eine neue Klasse “MyLabel” von “UILabel” abgeleitet anlegen. In den Initialisierungsmethoden wertet man nun den z.B. im InterfaceBuilder gesetzten Font (insbesondere Schnitt und Größe) aus und ersetzt ihn gegen den oder die eigenen mit denselben Parametern.

// File: MyLabel.m

@implementation MyLabel

// Custom initialization setting our own font
- (void)initLabel {

    CGFloat size = self.font.pointSize;
    NSString *name = self.font.fontName;
    NSUInteger length = name.length;

    // In case the preset font has Bold suffix,
    // we use our own font's bold variant
    if (length > 4 && [[name substringFromIndex:(length - 4)] compare:@"Bold"] == NSOrderedSame) {
        name = @"My-Font1-Bold";
    } else {
        name = @"My-Font1";
    }
    self.font = [UIFont fontWithName:name size:size];
}

// Override UILabel's init methods to call our custom
// intialization
- (id)initWithFrame:(CGRect)frame {

    self = [super initWithFrame:frame];
    if (self) [self initLabel];
    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder {

    self = [super initWithCoder:aDecoder];
    if (self) [self initLabel];
    return self;
}

@end

Pro eigenem Font erzeugt man sich nun so eine abgeleitete Klasse. Denkbar wäre sicher auch, ein Font-Mapping anzuwenden, bei dem dann z.B. “Helvetica” durch “MyFont1″ und “Noteworthy” durch “MyFont2″ ersetzt würde.

Anwendung

Im InterfaceBuilder braucht man jetzt nur noch bei den Labels, die den eigenen Font “MyFont1″ erhalten sollen, die Klasse vom Default “UILabel” auf “MyLabel” zu ändern. Die Parameter wie Schnitt, Größe, Farbe, Schatten etc. lassen sich wie gewohnt einstellen. Das genaue Erscheinungsbild sieht man aber nach wie vor nicht im InterfaceBuilder.

Zur Laufzeit (im Simulator oder auf dem iOS-Gerät) werden dann aber die Fonts wie in der Initialisierung realisiert ausgetauscht. Et voilà, “MyFont1″.

Ein Wermutstropfen bleibt jedoch: Durch die evtl. anderen Metriken gegenüber dem Original-Font sehen Umbrüche und Abstände anders als im InterfaceBuilder. Da muss man dann doch manuell dran.