I’m creating a cross-platform app, iOS and macOS (not MacOS Catalyst), in SwiftUI.
I’m supporting Dynamic Type through the .font(.title)
.font(.caption)
etc. modifiers.
This works great on iOS, however MacOS doesn’t support Dynamic Type.
I know users can change the font size on their Mac system wide through the display settings, but I would like to add an app preference where users can change the font size only for my app. Something similar like, for example, the mail app offers (Format > Style > Bigger)
I’m quite an experienced iOS dev,but this is my first MacOS app and my first real SwiftUI-only app. I’ve searched google and SO for half a day but can not find a way to do this.
Can this be done? Perhaps there is some kind of modifier to scale the font with a factor (and I could make that factor a global variable that would increase or decrease by the user changing this setting), or perhaps there is another way?
Here is an approach with a view modifier .dynamicFont
that takes a factor
.
Be aware that the standard sizes (for factor 1.0) reflect the standard macOS styles. You might cover iOS sizes as well there if you want to use it cross platform.
struct ContentView: View {
var body: some View {
HStack {
GroupBox {
VStack(alignment: .leading) {
Text("Hello, World!")
.font(.title)
Text("Hello, World!")
.font(.body)
Text("Hello, World!")
.font(.caption)
}
}
// example use
GroupBox {
VStack(alignment: .leading) {
Text("Hello, World!")
.dynamicFont(.title, factor: 1.2)
Text("Hello, World!")
.dynamicFont(.body, factor: 1.2)
Text("Hello, World!")
.dynamicFont(.caption, factor: 1.2)
}
}
}
}
}
enum DynamicFontStyle {
case largeTitle
case title
case headline
case body
case caption
// ...
// the standard sizes and weights are for MacOS!! and taken from
// https://developer.apple.com/design/human-interface-guidelines/foundations/typography/#specifications
func specs(factor: Double) -> Font {
switch self {
case .largeTitle:
return Font.system(size: 26 * factor, weight: .regular)
case .title:
return Font.system(size: 22 * factor, weight: .regular)
case .headline:
return Font.system(size: 13 * factor, weight: .bold)
case .body:
return Font.system(size: 13 * factor, weight: .regular)
case .caption:
return Font.system(size: 10 * factor, weight: .regular)
}
// ...
}
}
// View expension for ease of use
extension View {
func dynamicFont(_ style: DynamicFontStyle = .body, factor: Double = 1) -> some View {
self
.modifier(DynamicFontModifier(style: style, factor: factor))
}
}
// View Modifier
struct DynamicFontModifier: ViewModifier {
let style: DynamicFontStyle
let factor: Double
func body(content: Content) -> some View {
content
.font(style.specs(factor: factor))
}
}