How to make font size customizable in a macOS app

390 views Asked by At

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?

1

There are 1 answers

1
ChrisR On BEST ANSWER

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.

enter image description here

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))
    }
}