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 Font
and 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))