swiftuikituilabeluifont

How to change preferredFont globally in iOS app?


I've searched all over and can't seem to find a definitive (current) answer to this question.

I have a UILabel set up to use dynamic font sizing for accessibility reasons. It worked quite well with this line of code:

attributes[.font] = UIFont.preferredFont(forTextStyle: .body)

However, the default font is not working for me from a design standpoint.

When I try to use a custom font, by doing this:

attributes[.font] = UIFont(name: "Futura-Medium", size: 17)

It forces me to define size which I believe it overriding the ability to dynamically change the font.

I would love to figure out 1 of 2 solutions...

Either define the preferredFont universally as the font of my choice. Or a better line of code in which I can select a custom font and still have it adjust dynamically.

To recap... Currently my result is either correctly scaling text, but a generic font with this code:

var attributes = [NSAttributedString.Key: Any]()
attributes[.font] = UIFont.preferredFont(forTextStyle: .body)
attributes[.foregroundColor] = UIColor.black

Or it is a more suitable font, but does not scale at all with this code:

var attributes = [NSAttributedString.Key: Any]()
attributes[.font] = UIFont(name: "Futura-Medium", size: 17)
attributes[.foregroundColor] = UIColor.black

Solution

  • You could instantiate a preferred font object and use its point size to create your custom font object :

    attributes[.font] = UIFont(name: "Futura-Medium", size: UIFont.preferredFont(forTextStyle: .body).pointSize)
    

    To make it globally available you can add an extension on UIFont:

    import UIKit
    
    extension UIFont {
        private static let customFontName = "Futura-Medium"
        private static func customFont(withStyle style: UIFont.TextStyle) -> UIFont {
            let preferredFont = UIFont.preferredFont(forTextStyle: style)
            return UIFont(name: customFontName, size: preferredFont.pointSize) ?? preferredFont
        }
        static var bodyFont      : UIFont { customFont(withStyle: .body)       }
        static var largeTitleFont: UIFont { customFont(withStyle: .largeTitle) }
        static var title1Font    : UIFont { customFont(withStyle: .title1)     }
        static var title2Font    : UIFont { customFont(withStyle: .title2)     }
        static var title3Font    : UIFont { customFont(withStyle: .title3)     }
    }
    

    Now you can use it like:

    attributes[.font] = UIFont.bodyFont
    

    or

    attributes[.font] = UIFont.title1Font