How to change Dynamic Type to use different text styles

1.8k Views Asked by At

I want to use Dynamic Type for all texts in my app. The font I use is Apple's San Francisco.
I don't like the defaults one because they don't really use Bold for text.

Here is a list with all of them:

Style         Weight      Point size    Leading Tracking
--------------------------------------------------------
Large Title   Regular     34pt  41pt    11pt
Title 1       Regular     28pt  34pt    13pt
Title 2       Regular     22pt  28pt    16pt
Title 3       Regular     20pt  25pt    19pt
Headline      Semi-Bold   17pt  22pt.  -24pt
Body          Regular     17pt  22pt.  -24pt
Callout       Regular     16pt  21pt.  -20pt
Subhead       Regular     15pt  20pt.  -16pt
Footnote      Regular     13pt  18pt.  -6pt
Caption 1     Regular     12pt  16pt    0pt
Caption 2     Regular     11pt  13pt    6pt

So is there a way to configure how exactly the text styles should be ?

2

There are 2 best solutions below

1
On

One way to get different weights with Dynamic Type is to use other UIFont properties and methods in addition to preferredFont(forTextStyle:).

You can use the pointSize property combined with UIFont.systemFont(ofSize:weight:) to get a different weight:

let title1Font = UIFont.preferredFont(forTextStyle: .title1)
let title1PointSize = title1Font.pointSize
let boldTitle1Font = UIFont.systemFont(ofSize: title1PointSize, weight: .bold)

You can extend UIFont to provide any necessary conveniences. For example, if you need title1 and body styles in various weights, you can create this:

extension UIFont {

    static var title1: UIFont {
        return UIFont.preferredFont(forTextStyle: .title1)
    }
    static var body: UIFont {
        return UIFont.preferredFont(forTextStyle: .body)
    }

    func with(weight: UIFont.Weight) -> UIFont {
        return UIFont.systemFont(ofSize: pointSize, weight: weight)
    }

}

Then, accessing various sizes and fonts is super easy:

UIFont.title1.with(weight: .bold)
UIFont.body.with(weight: .semibold)
UIFont.body.with(weight: .light)
UIFont.title1 // normal weight
0
On

Swift 5

By expanding on tktsubota's answer and adding the following to it you can get your fonts all resizing dynamically for accessibility:

let font = UIFont.largeTitle.with(weight: .bold)
yourLabel.font = UIFontMetrics.default.scaledFont(for: font)
yourLabel.adjustsFontForContentSizeCategory = true

And tktsubota's UIFont extension:

extension UIFont {

    static var largeTitle: UIFont {
        return UIFont.preferredFont(forTextStyle: .largeTitle)
    }

    static var body: UIFont {
        return UIFont.preferredFont(forTextStyle: .body)
    }

    func with(weight: UIFont.Weight) -> UIFont {
        return UIFont.systemFont(ofSize: pointSize, weight: weight)
    }

}