d512
d512

Reputation: 34273

Detecting light fonts in iOS

I am trying to specify the font family of every label in my iOS app in a way that makes it fairly easy to change them later. I don't want to have to go through Interface Builder and reset every font on every screen. According to this post, I have created a method that will find all the fonts in a view and set them accordingly.

In my case, there are a few different font families I need to use based on whether the font is bold, italic, or light (e.g. skinny). These are all located in separate files such as "OpenSans-Semibold.ttf", "OpenSans-Italic.ttf", and "OpenSans-Light.ttf".

Ideally, I would like to be able to set the font to bold, italic, or light in Interface Builder, then have the code override just the font family, using the appropriate .ttf file. According to this post, I can pretty easily detect whether the font has been set to bold or italic, but finding out whether it's light or not doesn't seem to be working.

For the light fonts, the value of "traits" is 0x0--so no flags are set. Is there another way to detect light fonts?

Code looks like this:

- (void) setFontFamily:(UIView*)view
{
    if([view isKindOfClass:[UILabel class]])
    {
        UILabel* label = (UILabel*)view;

        UIFontDescriptorSymbolicTraits traits = label.font.fontDescriptor.symbolicTraits;
        BOOL bold = traits & UIFontDescriptorTraitBold;
        BOOL italic = traits & UIFontDescriptorTraitItalic;

        if(bold)
            [label setFont:[UIFont fontWithName:@"OpenSans-Semibold"size:label.font.pointSize]];
        else if(italic)
            [label setFont:[UIFont fontWithName:@"OpenSans-Italic"size:label.font.pointSize]];
        else if(light)
            [label setFont:[UIFont fontWithName:@"OpenSans-Light"size:label.font.pointSize]];
        else
            [label setFont:[UIFont fontWithName:@"OpenSans"size:label.font.pointSize]];
    }

    for(UIView* subView in view.subviews)
        [self setFontFamily:subView];
}

Upvotes: 1

Views: 885

Answers (1)

matt
matt

Reputation: 535999

Your entire approach to determining a font based on its characteristics is problematic:

else if(italic)
    [label setFont:
        [UIFont fontWithName:@"OpenSans-Italic"size:label.font.pointSize]];

You are hard-coding the font name based on the trait. Instead, ask the runtime for the font based on the name and trait. In this very simple example I find out what installed font, if any, is an italic variant of Gill Sans:

UIFont* f = [UIFont fontWithName:@"GillSans" size:15];
CTFontRef font2 =
    CTFontCreateCopyWithSymbolicTraits (
        (__bridge CTFontRef)f, 0, nil, 
         kCTFontItalicTrait, kCTFontItalicTrait);
UIFont* f2 = CFBridgingRelease(font2);

Note that this code is valid in iOS 7 only, where CTFontRef and UIFont are toll-free bridged to one another. In theory it should be possible to do this without C functions through UIFontDescriptor, but the last time I looked it was buggy and didn't work for all fonts (e.g. Gill Sans!).

That is what you should be doing: determine the symbolic and weight traits of your starting font, and then ask the runtime for the font that most close matches your requirements.

Upvotes: 1

Related Questions