How to scale system font in SwiftUI to support Dynamic Type?
In UIKit, I can change a UILabel's font size like this to support dynamic type using the system font:
UIFontMetrics.default.scaledFont(for: UIFont.systemFont(ofSize: 16))
Am I mistaken or is there no way to do such thing in SwiftUI? Can I only use the default font styles .title, etc. if I want to use the system font but also support Dynamic Type?
This solution from HackingWithSwift seems to only work with custom fonts, right?
Thanks in advance for any suggestions!
Solution 1:
The following approach works (tested with Xcode 11.2.1 / iOS 13.2.2)
var body: some View {
Text("Hello, World!") // direct text .font
.font(Font.system(size: UIFontMetrics.default.scaledValue(for: 16)))
}
as well as for view-based modifier
VStack {
Text("Hello, World!")
}
.font(Font.system(size: UIFontMetrics.default.scaledValue(for: 16)))
Solution 2:
You can create a ViewModifier
and a View
extension just like in the HackingWithSwift article you mentioned, but that uses the system font instead.
struct ScaledFont: ViewModifier {
// From the article:
// Asks the system to provide the current size category from the
// environment, which determines what level Dynamic Type is set to.
// The trick is that we don’t actually use it – we don’t care what the
// Dynamic Type setting is, but by asking the system to update us when
// it changes our UIFontMetrics code will be run at the same time,
// causing our font to scale correctly.
@Environment(\.sizeCategory) var sizeCategory
var size: CGFloat
func body(content: Content) -> some View {
let scaledSize = UIFontMetrics.default.scaledValue(for: size)
return content.font(.system(size: scaledSize))
}
}
extension View {
func scaledFont(size: CGFloat) -> some View {
return self.modifier(ScaledFont(size: size))
}
}
Usage example:
var body: some View {
Text("Hello, World!").scaledFont(size: 18)
}
You can use the Environment Overrides panel on Xcode 12 to test it.