How to use a custom font with dynamic text sizes in iOS7
Asked Answered
J

12

88

In iOS7 there are new API's for getting a font that is automatically adjusted to the text size the user has set in their preferences.

It looks something like this to use it:

UIFont *myFont = [UIFont fontWithDescriptor:[UIFontDescriptor preferredFontDescriptorWithTextStyle:UIFontTextStyleHeadline] size:0];

Now whatever text you assign this to will move up and down in font size as the user changes their system text size setting. (Remember to listen to the name:UIContentSizeCategoryDidChangeNotification notification and update your view to account for the change in size).

How do I use dynamic text with a font other than the default Helvetica-Neue?

Janelljanella answered 11/12, 2013 at 3:42 Comment(1)
From ios-11+, Apple give support to use custom dynamic font sizes. For implementation please have a look to this answer.Alicaalicante
J
132

Behind the scenes of that API, apple has some sort of lookup table that returns a specific font family, size, and sometimes symbolic traits (like bold) that (e.g. UIFontTextStyleHeadline) and the user's preferred text size. The latter is a string pulled off of the sharedApplication like this:

[UIApplication sharedApplication].preferredContentSizeCategory;

(I logged out all the default sizes/fonts/traits for Helvetica-Neue for the various dynamic text sizes). We've since added handling for the accessibility sizes, which is important.

So all you really have to do is build a similar lookup table. Our designer created a simple spreadsheet for me:

Font size lookup table

Notice that we added a couple styles (caption 3 & 4) to have 8 instead of 6 to choose from.

Then you'll want to put it someplace convenient, like a category on UIFontDescriptor. You'll want your method to return a UIFontDescriptor like Apple's API, so that it's still easy to adjust with symbolic traits, etc.

My category looks like this:

UIFontDescriptor+AvenirNext.h

#import <UIKit/UIKit.h>

extern NSString *const ANUIFontTextStyleCaption3;

@interface UIFontDescriptor (AvenirNext)

+(UIFontDescriptor *)preferredAvenirNextFontDescriptorWithTextStyle:(NSString *)style;

@end

UIFontDescriptor+AvenirNext.m

#import "UIFontDescriptor+AvenirNext.h"

NSString *const ANUIFontTextStyleCaption3 = @"ANUIFontTextStyleCaption3";
NSString *const ANUIFontTextStyleCaption4 = @"ANUIFontTextStyleCaption4";

@implementation UIFontDescriptor (AvenirNext)
+(UIFontDescriptor *)preferredAvenirNextFontDescriptorWithTextStyle:(NSString *)style {
    static dispatch_once_t onceToken;
    static NSDictionary *fontSizeTable;
    dispatch_once(&onceToken, ^{
        fontSizeTable = @{
          UIFontTextStyleHeadline: @{
                                    UIContentSizeCategoryAccessibilityExtraExtraExtraLarge: @26,
                                    UIContentSizeCategoryAccessibilityExtraExtraLarge: @25,
                                    UIContentSizeCategoryAccessibilityExtraLarge: @24,
                                    UIContentSizeCategoryAccessibilityLarge: @24,
                                    UIContentSizeCategoryAccessibilityMedium: @23,
                                    UIContentSizeCategoryExtraExtraExtraLarge: @23,
                                    UIContentSizeCategoryExtraExtraLarge: @22,
                                    UIContentSizeCategoryExtraLarge: @21,
                                    UIContentSizeCategoryLarge: @20,
                                    UIContentSizeCategoryMedium: @19,
                                    UIContentSizeCategorySmall: @18,
                                    UIContentSizeCategoryExtraSmall: @17,},

       UIFontTextStyleSubheadline: @{
                                    UIContentSizeCategoryAccessibilityExtraExtraExtraLarge: @24,
                                    UIContentSizeCategoryAccessibilityExtraExtraLarge: @23,
                                    UIContentSizeCategoryAccessibilityExtraLarge: @22,
                                    UIContentSizeCategoryAccessibilityLarge: @22,
                                    UIContentSizeCategoryAccessibilityMedium: @21,
                                    UIContentSizeCategoryExtraExtraExtraLarge: @21,
                                    UIContentSizeCategoryExtraExtraLarge: @20,
                                    UIContentSizeCategoryExtraLarge: @19,
                                    UIContentSizeCategoryLarge: @18,
                                    UIContentSizeCategoryMedium: @17,
                                    UIContentSizeCategorySmall: @16,
                                    UIContentSizeCategoryExtraSmall: @15,},

              UIFontTextStyleBody: @{
                                    UIContentSizeCategoryAccessibilityExtraExtraExtraLarge: @21,
                                    UIContentSizeCategoryAccessibilityExtraExtraLarge: @20,
                                    UIContentSizeCategoryAccessibilityExtraLarge: @19,
                                    UIContentSizeCategoryAccessibilityLarge: @19,
                                    UIContentSizeCategoryAccessibilityMedium: @18,
                                    UIContentSizeCategoryExtraExtraExtraLarge: @18,
                                    UIContentSizeCategoryExtraExtraLarge: @17,
                                    UIContentSizeCategoryExtraLarge: @16,
                                    UIContentSizeCategoryLarge: @15,
                                    UIContentSizeCategoryMedium: @14,
                                    UIContentSizeCategorySmall: @13,
                                    UIContentSizeCategoryExtraSmall: @12,},
          
          UIFontTextStyleCaption1: @{
                                    UIContentSizeCategoryAccessibilityExtraExtraExtraLarge: @19,
                                    UIContentSizeCategoryAccessibilityExtraExtraLarge: @18,
                                    UIContentSizeCategoryAccessibilityExtraLarge: @17,
                                    UIContentSizeCategoryAccessibilityLarge: @17,
                                    UIContentSizeCategoryAccessibilityMedium: @16,
                                    UIContentSizeCategoryExtraExtraExtraLarge: @16,
                                    UIContentSizeCategoryExtraExtraLarge: @16,
                                    UIContentSizeCategoryExtraLarge: @15,
                                    UIContentSizeCategoryLarge: @14,
                                    UIContentSizeCategoryMedium: @13,
                                    UIContentSizeCategorySmall: @12,
                                    UIContentSizeCategoryExtraSmall: @12,},
          
          UIFontTextStyleCaption2: @{
                                    UIContentSizeCategoryAccessibilityExtraExtraExtraLarge: @18,
                                    UIContentSizeCategoryAccessibilityExtraExtraLarge: @17,
                                    UIContentSizeCategoryAccessibilityExtraLarge: @16,
                                    UIContentSizeCategoryAccessibilityLarge: @16,
                                    UIContentSizeCategoryAccessibilityMedium: @15,
                                    UIContentSizeCategoryExtraExtraExtraLarge: @15,
                                    UIContentSizeCategoryExtraExtraLarge: @14,
                                    UIContentSizeCategoryExtraLarge: @14,
                                    UIContentSizeCategoryLarge: @13,
                                    UIContentSizeCategoryMedium: @12,
                                    UIContentSizeCategorySmall: @12,
                                    UIContentSizeCategoryExtraSmall: @11,},
          
        ANUIFontTextStyleCaption3: @{
                                    UIContentSizeCategoryAccessibilityExtraExtraExtraLarge: @17,
                                    UIContentSizeCategoryAccessibilityExtraExtraLarge: @16,
                                    UIContentSizeCategoryAccessibilityExtraLarge: @15,
                                    UIContentSizeCategoryAccessibilityLarge: @15,
                                    UIContentSizeCategoryAccessibilityMedium: @14,
                                    UIContentSizeCategoryExtraExtraExtraLarge: @14,
                                    UIContentSizeCategoryExtraExtraLarge: @13,
                                    UIContentSizeCategoryExtraLarge: @12,
                                    UIContentSizeCategoryLarge: @12,
                                    UIContentSizeCategoryMedium: @12,
                                    UIContentSizeCategorySmall: @11,
                                    UIContentSizeCategoryExtraSmall: @10,},

          UIFontTextStyleFootnote: @{
                                    UIContentSizeCategoryAccessibilityExtraExtraExtraLarge: @16,
                                    UIContentSizeCategoryAccessibilityExtraExtraLarge: @15,
                                    UIContentSizeCategoryAccessibilityExtraLarge: @14,
                                    UIContentSizeCategoryAccessibilityLarge: @14,
                                    UIContentSizeCategoryAccessibilityMedium: @13,
                                    UIContentSizeCategoryExtraExtraExtraLarge: @13,
                                    UIContentSizeCategoryExtraExtraLarge: @12,
                                    UIContentSizeCategoryExtraLarge: @12,
                                    UIContentSizeCategoryLarge: @11,
                                    UIContentSizeCategoryMedium: @11,
                                    UIContentSizeCategorySmall: @10,
                                    UIContentSizeCategoryExtraSmall: @10,},

          ANUIFontTextStyleCaption4: @{
                                    UIContentSizeCategoryAccessibilityExtraExtraExtraLarge: @15,
                                    UIContentSizeCategoryAccessibilityExtraExtraLarge: @14,
                                    UIContentSizeCategoryAccessibilityExtraLarge: @13,
                                    UIContentSizeCategoryAccessibilityLarge: @13,
                                    UIContentSizeCategoryAccessibilityMedium: @12,
                                    UIContentSizeCategoryExtraExtraExtraLarge: @12,
                                    UIContentSizeCategoryExtraExtraLarge: @11,
                                    UIContentSizeCategoryExtraLarge: @11,
                                    UIContentSizeCategoryLarge: @10,
                                    UIContentSizeCategoryMedium: @10,
                                    UIContentSizeCategorySmall: @9,
                                    UIContentSizeCategoryExtraSmall: @9,},
        };
    });
    
    
    NSString *contentSize = [UIApplication sharedApplication].preferredContentSizeCategory;
    return [UIFontDescriptor fontDescriptorWithName:[self preferredFontName] size:((NSNumber *)fontSizeTable[style][contentSize]).floatValue];
}
+(UIFontDescriptor *)preferredAvenirNextDemiBoldFontDescriptorWithTextStyle:(NSString *)style {
    return [[self preferredAvenirNextFontDescriptorWithTextStyle:style] fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold];
}

+(UIFontDescriptor *)preferredAvenirNextBoldFontDescriptorWithTextStyle:(NSString *)style {
    return [UIFontDescriptor fontDescriptorWithName:[self preferredBoldFontName] size:[self preferredAvenirNextFontDescriptorWithTextStyle:style].pointSize];
}

+(NSString *)preferredFontName {
    return @"AvenirNext-Medium";
}
+(NSString *)preferredBoldFontName {
    return @"AvenirNext-Bold";
}

@end

We chose to use the same base font AvenirNext-Medium, and then bold and such via symbolic traits, but you could get crazy and specify different weight variants on your font as part of your lookup table as well if you wanted, like AvenirNext-ExtraBold.

That's all there is to it! We use it like this:

[UIFont fontWithDescriptor:[UIFontDescriptor preferredAvenirNextFontDescriptorWithTextStyle:UIFontTextStyleHeadline] size: 0]
Janelljanella answered 11/12, 2013 at 3:42 Comment(10)
Excellent solution, but you're missing the accessibility constants: UIContentSizeCategoryAccessibilityMedium, UIContentSizeCategoryAccessibilityLarge, etc.Do
Why not extend UIFont, so that you can just use: [UIFont preferredAvenirFontForTextStyle:UIFontTextStyleHeadline]? Size is redundant in the example you give at the bottom?Mouseear
@richarddas simply to keep with Apple's pattern. A size of 0 is ignored, and simply passes through the correct size from the descriptor.Janelljanella
Updated to integrate the constants Ben Jackson suggested. Also examples of bold and extra bold provided.Janelljanella
Sorry for re-awakening this somewhat old question, but just to comment on the remark about not being able to store the dictionary on the class itself, you could use associated objects (nshipster.com/associated-objects), seeing as classes are also objects you can just associate the lookup table with the class.Morn
Hi, I am using Xcode 6.0.1. I used the above code to set the custom font for the label. However i was able to find the custom font in Interface builder, but failed to apply via this code. I used Sansation font file. Please help me. Thanks.Cicatrix
Hi, i applied the above mentioned font and a couple more with the same code without any modification, and it worked. But in some cases it doesn't. This means that there should be something wrong with my font file.Cicatrix
As of iOS 8.4 Apple tweaked the font sizes a bit: gist.github.com/klaas/750f489e2390389ab812Rocketry
How does the Larger Accessibility Sizes option affect this matrix?Manganin
[UIApplication sharedApplication].preferredContentSizeCategory always returning to me same value ** UICTContentSizeCategoryL** even after changing text size from accessibilityKisner
S
15

This is how I do it in Swift. I like this because it's more general, it only requires one table, and it should work well with any font. First I wrote a generalized multiplier (in a getter).

var fontSizeMultiplier : CGFloat {
    get {
        switch UIApplication.sharedApplication().preferredContentSizeCategory {
        case UIContentSizeCategoryAccessibilityExtraExtraExtraLarge: return 23 / 16
        case UIContentSizeCategoryAccessibilityExtraExtraLarge: return 22 / 16
        case UIContentSizeCategoryAccessibilityExtraLarge: return 21 / 16
        case UIContentSizeCategoryAccessibilityLarge: return 20 / 16
        case UIContentSizeCategoryAccessibilityMedium: return 19 / 16
        case UIContentSizeCategoryExtraExtraExtraLarge: return 19 / 16
        case UIContentSizeCategoryExtraExtraLarge: return 18 / 16
        case UIContentSizeCategoryExtraLarge: return 17 / 16
        case UIContentSizeCategoryLarge: return 1.0
        case UIContentSizeCategoryMedium: return 15 / 16
        case UIContentSizeCategorySmall: return 14 / 16
        case UIContentSizeCategoryExtraSmall: return 13 / 16
        default: return 1.0
        }
    }
}

Then I update the font (e.g., in the observer) using a UIFontDescriptor like this:

textView.font = UIFont(descriptor: fontDescriptor!, size: fontDescriptor!.pointSize * fontSizeMultiplier)
Sharpshooter answered 13/10, 2015 at 23:58 Comment(2)
This won't work as the pointSize will increase exponentially everytime you update the size in settings. If you set a default font size, you can use that as a base and multiply that by the fontSizeMultiplier.Winniewinnifred
@Winniewinnifred - This works well. I've been using it for years. Since it's returning literal values I don't see how you think it would increase when you change the settings.Sharpshooter
C
13

In iOS 11 UIFontMetrics class was introduced. Create a FontMetrics object for the text style that you're interested in. Then choose any font you want, sized for the standard dynamic type size. And then you can ask the FontMetrics object to scale that font given the user's current settings.

let bodyMetrics = UIFontMetrics(forTextStyle: .body)
let standardFont = ... // any font you want, for standard type size
let font = bodyMetrics.scaledFont(for: standardFont)
Cormick answered 15/8, 2017 at 8:27 Comment(0)
V
8

@Bob Spryn code rewritten with swift:

import UIKit

extension UIFontDescriptor {

    private struct SubStruct {
        static var preferredFontName: NSString = "OEMeodedPashutPro-Regular"
    }

    class func preferredDescriptor(textStyle: NSString) -> UIFontDescriptor {
        struct Static {
            static var onceToken : dispatch_once_t = 0
            static var fontSizeTable : NSDictionary = NSDictionary()
        }

        dispatch_once(&Static.onceToken) {
            Static.fontSizeTable = [
                UIFontTextStyleHeadline: [
                    UIContentSizeCategoryAccessibilityExtraExtraExtraLarge: 26,
                    UIContentSizeCategoryAccessibilityExtraExtraLarge: 25,
                    UIContentSizeCategoryAccessibilityExtraLarge: 24,
                    UIContentSizeCategoryAccessibilityLarge: 24,
                    UIContentSizeCategoryAccessibilityMedium: 23,
                    UIContentSizeCategoryExtraExtraExtraLarge: 23,
                    UIContentSizeCategoryExtraExtraLarge: 22,
                    UIContentSizeCategoryExtraLarge: 21,
                    UIContentSizeCategoryLarge: 20,
                    UIContentSizeCategoryMedium: 19,
                    UIContentSizeCategorySmall: 18,
                    UIContentSizeCategoryExtraSmall: 17
                ],
                UIFontTextStyleSubheadline: [
                    UIContentSizeCategoryAccessibilityExtraExtraExtraLarge: 24,
                    UIContentSizeCategoryAccessibilityExtraExtraLarge: 23,
                    UIContentSizeCategoryAccessibilityExtraLarge: 22,
                    UIContentSizeCategoryAccessibilityLarge: 22,
                    UIContentSizeCategoryAccessibilityMedium: 21,
                    UIContentSizeCategoryExtraExtraExtraLarge: 21,
                    UIContentSizeCategoryExtraExtraLarge: 20,
                    UIContentSizeCategoryExtraLarge: 19,
                    UIContentSizeCategoryLarge: 18,
                    UIContentSizeCategoryMedium: 17,
                    UIContentSizeCategorySmall: 16,
                    UIContentSizeCategoryExtraSmall: 15
                ],
                UIFontTextStyleBody: [
                    UIContentSizeCategoryAccessibilityExtraExtraExtraLarge: 21,
                    UIContentSizeCategoryAccessibilityExtraExtraLarge: 20,
                    UIContentSizeCategoryAccessibilityExtraLarge: 19,
                    UIContentSizeCategoryAccessibilityLarge: 19,
                    UIContentSizeCategoryAccessibilityMedium: 18,
                    UIContentSizeCategoryExtraExtraExtraLarge: 18,
                    UIContentSizeCategoryExtraExtraLarge: 17,
                    UIContentSizeCategoryExtraLarge: 16,
                    UIContentSizeCategoryLarge: 15,
                    UIContentSizeCategoryMedium: 14,
                    UIContentSizeCategorySmall: 13,
                    UIContentSizeCategoryExtraSmall: 12
                ],
                UIFontTextStyleCaption1: [
                    UIContentSizeCategoryAccessibilityExtraExtraExtraLarge: 19,
                    UIContentSizeCategoryAccessibilityExtraExtraLarge: 18,
                    UIContentSizeCategoryAccessibilityExtraLarge: 17,
                    UIContentSizeCategoryAccessibilityLarge: 17,
                    UIContentSizeCategoryAccessibilityMedium: 16,
                    UIContentSizeCategoryExtraExtraExtraLarge: 16,
                    UIContentSizeCategoryExtraExtraLarge: 16,
                    UIContentSizeCategoryExtraLarge: 15,
                    UIContentSizeCategoryLarge: 14,
                    UIContentSizeCategoryMedium: 13,
                    UIContentSizeCategorySmall: 12,
                    UIContentSizeCategoryExtraSmall: 12
                ],
                UIFontTextStyleCaption2: [
                    UIContentSizeCategoryAccessibilityExtraExtraExtraLarge: 18,
                    UIContentSizeCategoryAccessibilityExtraExtraLarge: 17,
                    UIContentSizeCategoryAccessibilityExtraLarge: 16,
                    UIContentSizeCategoryAccessibilityLarge: 16,
                    UIContentSizeCategoryAccessibilityMedium: 15,
                    UIContentSizeCategoryExtraExtraExtraLarge: 15,
                    UIContentSizeCategoryExtraExtraLarge: 14,
                    UIContentSizeCategoryExtraLarge: 14,
                    UIContentSizeCategoryLarge: 13,
                    UIContentSizeCategoryMedium: 12,
                    UIContentSizeCategorySmall: 12,
                    UIContentSizeCategoryExtraSmall: 11
                ],
                UIFontTextStyleFootnote: [
                    UIContentSizeCategoryAccessibilityExtraExtraExtraLarge: 16,
                    UIContentSizeCategoryAccessibilityExtraExtraLarge: 15,
                    UIContentSizeCategoryAccessibilityExtraLarge: 14,
                    UIContentSizeCategoryAccessibilityLarge: 14,
                    UIContentSizeCategoryAccessibilityMedium: 13,
                    UIContentSizeCategoryExtraExtraExtraLarge: 13,
                    UIContentSizeCategoryExtraExtraLarge: 12,
                    UIContentSizeCategoryExtraLarge: 12,
                    UIContentSizeCategoryLarge: 11,
                    UIContentSizeCategoryMedium: 11,
                    UIContentSizeCategorySmall: 10,
                    UIContentSizeCategoryExtraSmall: 10
                ],
            ]
        }

        let contentSize = UIApplication.sharedApplication().preferredContentSizeCategory

        let style = Static.fontSizeTable[textStyle] as NSDictionary

        return UIFontDescriptor(name: SubStruct.preferredFontName, size: CGFloat((style[contentSize] as NSNumber).floatValue))
    }

}

Usage:

UIFont(descriptor: UIFontDescriptor.preferredDescriptor(UIFontTextStyleBody), size: 0)
Virgy answered 7/2, 2015 at 17:43 Comment(2)
Xcode 7.2 made me change the last two lines to: let style = Static.fontSizeTable[textStyle] as! NSDictionary and return UIFontDescriptor(name: SubStruct.preferredFontName as String, size: CGFloat((style[contentSize] as! NSNumber).floatValue))Nauplius
It would be really cool if I could do something that shows the preferred font in Storyboard. Maybe by subclassing the text elements.Manganin
E
7

Try this:

UIFontDescriptor *userHeadLineFont = [UIFontDescriptor preferredFontDescriptorWithTextStyle:UIFontTextStyleHeadline];
CGFloat userHeadLineFontSize = [userHeadLineFont pointSize];
myFont = [UIFont fontWithName:@"Baskerville" size:userHeadLineFontSize];

But keep in mind that this code is only an approximation (Dynamic Type does much more than just scale font size).

Eaddy answered 9/4, 2014 at 15:9 Comment(4)
Can you elaborate on the paranthesis? What more than scaling should I take into account?Stearoptene
There is a mapping between the font "dynamic type" and the font really used. For example little font can become bold. I don't know the exact mapping. See the last image ("dynamic type optical scaling") in this article: fireballed.org/linked/2013/07/08/ios-7-type to better understand.Eaddy
This one does the same as the approved correct answer, but kinda difference in the number of lines. Great solution. The same in SWIFT #35356195Pussyfoot
Here's a working link to the article mentioned by @Eaddy in the comments: Beyond Helvetica: The Real Story Behind Fonts in iOS 7Sidestroke
U
6

Similar to @bill-weinman's approach, I took the scales, and broke it out into a function that doesn't rely on a given font size of 16.

/// The font scale for a given font size.
///
/// - seealso: [Source](https://mcmap.net/q/236911/-how-to-use-a-custom-font-with-dynamic-text-sizes-in-ios7)
///
/// - Parameter fontSize: The font size.
/// - Returns: The font scale
public func fontScale(for fontSize: CGFloat) -> CGFloat {
    switch UIApplication.shared.preferredContentSizeCategory {
    case UIContentSizeCategory.accessibilityExtraExtraExtraLarge:    return (fontSize + 8) / fontSize
    case UIContentSizeCategory.accessibilityExtraExtraLarge:         return (fontSize + 7) / fontSize
    case UIContentSizeCategory.accessibilityExtraLarge:              return (fontSize + 6) / fontSize
    case UIContentSizeCategory.accessibilityLarge:                   return (fontSize + 5) / fontSize
    case UIContentSizeCategory.accessibilityMedium:                  return (fontSize + 4) / fontSize
    case UIContentSizeCategory.extraExtraExtraLarge:                 return (fontSize + 3) / fontSize
    case UIContentSizeCategory.extraExtraLarge:                      return (fontSize + 2) / fontSize
    case UIContentSizeCategory.extraLarge:                           return (fontSize + 1) / fontSize
    case UIContentSizeCategory.large:                                return 1.0
    case UIContentSizeCategory.medium:                               return (fontSize - 1) / fontSize
    case UIContentSizeCategory.small:                                return (fontSize - 2) / fontSize
    case UIContentSizeCategory.extraSmall:                           return (fontSize - 3) / fontSize
    default:
        return 1.0
    }
}

It can then be used with custom fonts like this:

/// Light font of specified size.
///
/// - Parameter size: Font size.
/// - Returns: Light font of specified size.
func lightFont(ofSize size: CGFloat) -> UIFont {
    let scaledSize = size * fontScale(for: size)

    return UIFont(name: "HelveticaNeueLTStd-Lt", size: scaledSize)!
}
Untouchable answered 9/5, 2017 at 19:37 Comment(2)
This is not bad if you're at a stage where you do not want to fine tune everything. Also if your custom font is rather small and needs some scaling by default.Hemmer
FYI - my approach doesn't rely on font size. It returns a value based on a ratio. It works fine with custom/scaled fonts.Sharpshooter
R
3

In iOS 11 you can use:

var customFont = UIFont.systemFont(ofSize: 17.0)
if #available(iOS 11.0, *) {
    customFont = UIFontMetrics.default.scaledFont(for: customFont)
}
// use customFont...

See also Building Apps with Dynamic Type WWDC 2017 - Session 245 - iOS time 8:34.

Riding answered 22/10, 2017 at 22:45 Comment(0)
O
2

Swift 2.1-3.0 code based on @smartDonkey's port of @Bob Spryn code. Also updated with the Apple sizes from @Klaas.

import UIKit

extension UIFontDescriptor {

    private struct SubStruct {
        static var preferredFontName: String = "Roboto-Light"
    }

    class func preferredDescriptor(textStyle: NSString) -> UIFontDescriptor {
        struct Static {
            static var onceToken : dispatch_once_t = 0
            static var fontSizeTable : NSDictionary = NSDictionary()
        }

        dispatch_once(&Static.onceToken) {
            Static.fontSizeTable = [
                UIFontTextStyleHeadline: [
                    UIContentSizeCategoryAccessibilityExtraExtraExtraLarge: 23,
                    UIContentSizeCategoryAccessibilityExtraExtraLarge: 23,
                    UIContentSizeCategoryAccessibilityExtraLarge: 23,
                    UIContentSizeCategoryAccessibilityLarge: 23,
                    UIContentSizeCategoryAccessibilityMedium: 23,
                    UIContentSizeCategoryExtraExtraExtraLarge: 23,
                    UIContentSizeCategoryExtraExtraLarge: 21,
                    UIContentSizeCategoryExtraLarge: 19,
                    UIContentSizeCategoryLarge: 17,
                    UIContentSizeCategoryMedium: 16,
                    UIContentSizeCategorySmall: 15,
                    UIContentSizeCategoryExtraSmall: 14
                ],
                UIFontTextStyleSubheadline: [
                    UIContentSizeCategoryAccessibilityExtraExtraExtraLarge: 21,
                    UIContentSizeCategoryAccessibilityExtraExtraLarge: 21,
                    UIContentSizeCategoryAccessibilityExtraLarge: 21,
                    UIContentSizeCategoryAccessibilityLarge: 21,
                    UIContentSizeCategoryAccessibilityMedium: 21,
                    UIContentSizeCategoryExtraExtraExtraLarge: 21,
                    UIContentSizeCategoryExtraExtraLarge: 19,
                    UIContentSizeCategoryExtraLarge: 17,
                    UIContentSizeCategoryLarge: 15,
                    UIContentSizeCategoryMedium: 14,
                    UIContentSizeCategorySmall: 13,
                    UIContentSizeCategoryExtraSmall: 12
                ],
                UIFontTextStyleBody: [
                    UIContentSizeCategoryAccessibilityExtraExtraExtraLarge: 53,
                    UIContentSizeCategoryAccessibilityExtraExtraLarge: 47,
                    UIContentSizeCategoryAccessibilityExtraLarge: 40,
                    UIContentSizeCategoryAccessibilityLarge: 33,
                    UIContentSizeCategoryAccessibilityMedium: 28,
                    UIContentSizeCategoryExtraExtraExtraLarge: 23,
                    UIContentSizeCategoryExtraExtraLarge: 21,
                    UIContentSizeCategoryExtraLarge: 19,
                    UIContentSizeCategoryLarge: 17,
                    UIContentSizeCategoryMedium: 16,
                    UIContentSizeCategorySmall: 15,
                    UIContentSizeCategoryExtraSmall: 14
                ],
                UIFontTextStyleCaption1: [
                    UIContentSizeCategoryAccessibilityExtraExtraExtraLarge: 18,
                    UIContentSizeCategoryAccessibilityExtraExtraLarge: 18,
                    UIContentSizeCategoryAccessibilityExtraLarge: 18,
                    UIContentSizeCategoryAccessibilityLarge: 18,
                    UIContentSizeCategoryAccessibilityMedium: 18,
                    UIContentSizeCategoryExtraExtraExtraLarge: 18,
                    UIContentSizeCategoryExtraExtraLarge: 16,
                    UIContentSizeCategoryExtraLarge: 14,
                    UIContentSizeCategoryLarge: 12,
                    UIContentSizeCategoryMedium: 11,
                    UIContentSizeCategorySmall: 11,
                    UIContentSizeCategoryExtraSmall: 11
                ],
                UIFontTextStyleCaption2: [
                    UIContentSizeCategoryAccessibilityExtraExtraExtraLarge: 17,
                    UIContentSizeCategoryAccessibilityExtraExtraLarge: 17,
                    UIContentSizeCategoryAccessibilityExtraLarge: 17,
                    UIContentSizeCategoryAccessibilityLarge: 17,
                    UIContentSizeCategoryAccessibilityMedium: 17,
                    UIContentSizeCategoryExtraExtraExtraLarge: 17,
                    UIContentSizeCategoryExtraExtraLarge: 15,
                    UIContentSizeCategoryExtraLarge: 13,
                    UIContentSizeCategoryLarge: 11,
                    UIContentSizeCategoryMedium: 11,
                    UIContentSizeCategorySmall: 11,
                    UIContentSizeCategoryExtraSmall: 11
                ],
                UIFontTextStyleFootnote: [
                    UIContentSizeCategoryAccessibilityExtraExtraExtraLarge: 19,
                    UIContentSizeCategoryAccessibilityExtraExtraLarge: 19,
                    UIContentSizeCategoryAccessibilityExtraLarge: 19,
                    UIContentSizeCategoryAccessibilityLarge: 19,
                    UIContentSizeCategoryAccessibilityMedium: 19,
                    UIContentSizeCategoryExtraExtraExtraLarge: 19,
                    UIContentSizeCategoryExtraExtraLarge: 17,
                    UIContentSizeCategoryExtraLarge: 15,
                    UIContentSizeCategoryLarge: 13,
                    UIContentSizeCategoryMedium: 12,
                    UIContentSizeCategorySmall: 12,
                    UIContentSizeCategoryExtraSmall: 12
                ],
            ]
        }

        let contentSize = UIApplication.sharedApplication().preferredContentSizeCategory
        let style = Static.fontSizeTable[textStyle] as! NSDictionary
        return UIFontDescriptor(name: SubStruct.preferredFontName, size: CGFloat((style[contentSize] as! NSNumber).floatValue))
    }

}
Openmouthed answered 17/2, 2016 at 20:34 Comment(1)
Errors on Swift 3 with your solution: 'dispatch_once_t' is unavailable in Swift: Use lazily initialized globals insteadProcedure
M
2

Here is my take on @Gobe's answer, in Swift 3:

extension UIFontDescriptor {

@nonobjc static var fontSizeTable: [UIFontTextStyle : [UIContentSizeCategory : CGFloat]] = {
    return [
        .headline: [
            .accessibilityExtraExtraExtraLarge: 23,
            .accessibilityExtraExtraLarge: 23,
            .accessibilityExtraLarge: 23,
            .accessibilityLarge: 23,
            .accessibilityMedium: 23,
            .extraExtraExtraLarge: 23,
            .extraExtraLarge: 21,
            .extraLarge: 19,
            .large: 17,
            .medium: 16,
            .small: 15,
            .extraSmall: 14],
        .subheadline: [
            .accessibilityExtraExtraExtraLarge: 21,
            .accessibilityExtraExtraLarge: 21,
            .accessibilityExtraLarge: 21,
            .accessibilityLarge: 21,
            .accessibilityMedium: 21,
            .extraExtraExtraLarge: 21,
            .extraExtraLarge: 19,
            .extraLarge: 17,
            .large: 15,
            .medium: 14,
            .small: 13,
            .extraSmall: 12],
        .body: [
            .accessibilityExtraExtraExtraLarge: 53,
            .accessibilityExtraExtraLarge: 47,
            .accessibilityExtraLarge: 40,
            .accessibilityLarge: 33,
            .accessibilityMedium: 28,
            .extraExtraExtraLarge: 23,
            .extraExtraLarge: 21,
            .extraLarge: 19,
            .large: 17,
            .medium: 16,
            .small: 15,
            .extraSmall: 14],
        .caption1: [
            .accessibilityExtraExtraExtraLarge: 18,
            .accessibilityExtraExtraLarge: 18,
            .accessibilityExtraLarge: 18,
            .accessibilityLarge: 18,
            .accessibilityMedium: 18,
            .extraExtraExtraLarge: 18,
            .extraExtraLarge: 16,
            .extraLarge: 14,
            .large: 12,
            .medium: 11,
            .small: 11,
            .extraSmall: 11],
        .caption2: [
            .accessibilityExtraExtraExtraLarge: 17,
            .accessibilityExtraExtraLarge: 17,
            .accessibilityExtraLarge: 17,
            .accessibilityLarge: 17,
            .accessibilityMedium: 17,
            .extraExtraExtraLarge: 17,
            .extraExtraLarge: 15,
            .extraLarge: 13,
            .large: 11,
            .medium: 11,
            .small: 11,
            .extraSmall: 11],
        .footnote: [
            .accessibilityExtraExtraExtraLarge: 19,
            .accessibilityExtraExtraLarge: 19,
            .accessibilityExtraLarge: 19,
            .accessibilityLarge: 19,
            .accessibilityMedium: 19,
            .extraExtraExtraLarge: 19,
            .extraExtraLarge: 17,
            .extraLarge: 15,
            .large: 13,
            .medium: 12,
            .small: 12,
            .extraSmall: 12],
    ]
}()

class func currentPreferredSize(textStyle: UIFontTextStyle = .body) -> CGFloat {
    let contentSize = UIApplication.shared.preferredContentSizeCategory
    guard let style = fontSizeTable[textStyle], let fontSize = style[contentSize] else { return 17 }
    return fontSize
}

class func preferredFontDescriptor(fontName: String = "SnellRoundhand", textStyle: UIFontTextStyle = .body) -> UIFontDescriptor {
    return UIFontDescriptor(name: fontName, size: currentPreferredSize())
}
}
Menstruation answered 1/3, 2017 at 21:37 Comment(1)
Swift5 version has been added to #41798580Yardarm
W
1

This is how I update the font of a prefferedFontForTextStyle:

UIFont *font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
UIFontDescriptor *fontDesc = [font fontDescriptor];
fontDesc = [fontDesc fontDescriptorByAddingAttributes:@{UIFontDescriptorNameAttribute : @"Helvetica",
                                                        UIFontDescriptorSizeAttribute : @16}];

font = [UIFont fontWithDescriptor:fontDesc
                             size:[fontDesc pointSize]];
Whorled answered 8/11, 2014 at 19:39 Comment(0)
F
1

Just wanted to jump in and say that there's a library out there to help integrate custom fonts and deal with the Dynamic Type size changes. It's called, helpfully, Font (https://github.com/adamyanalunas/Font) and instead of being a magic solution it sets up a structure for handling each custom font differently while removing the boilerplate.

n.b. I'm the author of this lil' library and I think it's neat.

Fen answered 29/1, 2016 at 19:38 Comment(0)
R
0

Starting from iOS 11 you can programmatically adjust custom fonts configured in visual editor:

  1. Configure your custom font using visual editor
  2. Adjust font size in viewDidLoad method:
@IBOutlet weak var leftLangLabel: UILabel!

override func viewDidLoad() {
    super.viewDidLoad()

    leftLangLabel.font = UIFontMetrics.default.scaledFont(for: leftLangLabel.font)
}
Rosetta answered 23/4, 2019 at 8:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.