isak.me - a blog by isak solheim

Bi-weekly updates about things that interest me, things I have built and things I have learned.

How to use custom fonts in SwiftUI

In this article, I will show you how to build a custom font modifier CustomFontModifier in SwiftUI, which can be used for typography in your iOS app.

Text("Juhu!")
    .customFont(.bold(size: .h1))

Creating a custom Font

When building an app using a custom font, I’ve found that creating a custom font modifier CustomFontModifier is the best solution.

To implement this, start by creating a new file Font.swift, where we define our custom font, alongside it’s typographic sizes:

import SwiftUI

enum Font {
    case light(size: Size)
    case regular(size: Size)
    case medium(size: Size)
    case bold(size: Size)

    enum Size: CGFloat {
        case h1 = 21
        case h2 = 16
        case h3 = 14
        case h4 = 12
    }

    var font: UIFont {
        switch self {
        case let .light(size):
            return UIFontMetrics(forTextStyle: .body).scaledFont(for: R.font.osloSansLight(size: size.rawValue)!)
        case let .regular(size):
            return UIFontMetrics(forTextStyle: .body).scaledFont(for: R.font.osloSansRegular(size: size.rawValue)!)
        case let .medium(size):
            return UIFontMetrics(forTextStyle: .body).scaledFont(for: R.font.osloSansMedium(size: size.rawValue)!)
        case let .bold(size):
            return UIFontMetrics(forTextStyle: .body).scaledFont(for: R.font.osloSansBold(size: size.rawValue)!)
        }
    }
}

I’ve placed my inside /Resources , and access it with the

static func osloSansRegular(size: CGFloat) -> UIFont?

function. In my implementation, I am using UIFontMetrics to support Dynamic Type. If this behavior is not wanted, you could simply return the font directly:

var font: UIFont {
    switch self {
    case let .light(size):
        return R.font.osloSansLight(size: size.rawValue)!
    case let .regular(size):
        return R.font.osloSansRegular(size: size.rawValue)!
    case let .medium(size):
        return R.font.osloSansMedium(size: size.rawValue)!
    case let .bold(size):
        return R.font.osloSansBold(size: size.rawValue)!
    }
}

Custom Font Modifier

In a new file CustomFontModifier.swift, we implement the custom modifier, accepting a Fontand applying it the the content:

import SwiftUI

struct CustomFontModifier: ViewModifier {
    var font: Font

    func body(content: Content) -> some View {
        let uiFont = font.font
        return content.font(.custom(uiFont.fontName, size: uiFont.pointSize))
    }
}

extension View {
    func customFont(_ font: Font) -> some View {
        self.modifier(CustomFontModifier(font: font))
    }
}

Usage

With our custom font modifier, we can apply it to all components that require our custom font:

Text("Custom Font Engaged")
    .customFont(.regular(size: .h2))