ios – Certain fonts not applying to specific views


I’ve added custom fonts to my project and have successfully been able to use each font to stylize text but only in a settings menu:

class AppearanceManager: ObservableObject {

    @Published var Font: String = "System" {
        didSet {
            saveFont()
            objectWillChange.send()
            print("Set font to \(Font)")
            print("Corresponding font name: \(fonts[Font])")
        }
    }
    
    public let fonts = ["System" : "system-default", // unrecognized name defaults to system font
                        "Courier Prime" : "CourierPrime-Regular",
                        "JetBrains Mono" : "JetBrainsMono-Regular",
                        "Roboto" : "RobotoMono-Regular",
                        "Ubuntu" : "UbuntuMono-Regular",
                        "Victor" : "VictorMono-Regular",
                        "Times New Roman" : "TimesNewRomanPSMT",
                        "Trebuchet" : "TrebuchetMS"
    ]
    
    init() {
        loadFont()
        
        // used for debugging
        for family in UIFont.familyNames.sorted() {
            let names = UIFont.fontNames(forFamilyName: family)
            print("Family: \(family) Font names: \(names)")
        }
    }
    
    private let fontKey = "FontKey"
    
    private func saveFont() {
        UserDefaults.standard.set(Font, forKey: fontKey)
    }
    
    private func loadFont() {
        if let savedFont = UserDefaults.standard.value(forKey: fontKey) as? String {
            Font = savedFont
        }
    }
}

struct SettingsView: View {
    @EnvironmentObject var appearanceManager: AppearanceManager
    
    var body: some View {
        Form {
            FontSelectionView()
        }
        .navigationTitle("Settings")
    }
}

struct FontSelectionView: View {
    @EnvironmentObject var appearanceManager: AppearanceManager

    var body: some View {
        Section(header: Text("Fonts")) {
            VStack(alignment: .leading) {
                ForEach(appearanceManager.fonts.keys.sorted(), id: \.self) { fontName in
                    FontButton(name: fontName)
                }
                .padding(.vertical, 5)
            }
        }
    }
}

struct FontButton: View {
    @EnvironmentObject var appearanceManager: AppearanceManager

    let name: String
    var isSelected: Bool {
        appearanceManager.Font == name
    }

    var body: some View {
        HStack {
            Text(name)
                .font(.custom(appearanceManager.fonts[name] ?? "", size: 17, relativeTo: .body))
            Spacer()
            Circle()
                .frame(width: 20, height: 20)
                .foregroundColor(isSelected ? .secondary : .clear)
                .overlay(
                    Circle()
                        .stroke(Color.primary, lineWidth: 2)
                )
        }
        .foregroundColor(.secondary)
        .onTapGesture {
            withAnimation {
                appearanceManager.Font = name
            }
        }
    }
}

The code above can be used to apply each font to text:
enter image description here

However certain fonts (not just custom fonts I added to my project, but also built-in fonts such as Trebuchet) are not being applied to text elements throughout my app:

struct PostView: View {
    @EnvironmentObject var appearanceManager: AppearanceManager
    
    var body: some View {
        ScrollView {
            VStack(alignment: .leading, spacing: 16) {
                
                Text("Hello World")
                    // below only works for certain fonts
                    .font(.custom(appearanceManager.Font, size: 30, relativeTo: .title))

            }
            .padding()
        }
    }
}

I have injected the EnvironmentObject to the root view of my app

@main
struct MyApp: App {
    
    @StateObject private var appearanceManager = AppearanceManager()

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(appearanceManager)
        }
    }
}

I have also printed all available fonts and determined that the actual font name is being published:

// prints in init() method: 
...
Family: Times New Roman Font names: ["TimesNewRomanPSMT", "TimesNewRomanPS-ItalicMT", "TimesNewRomanPS-BoldMT", "TimesNewRomanPS-BoldItalicMT"]
Family: Trebuchet MS Font names: ["TrebuchetMS", "TrebuchetMS-Italic", "TrebuchetMS-Bold", "Trebuchet-BoldItalic"]
Family: Ubuntu Mono Font names: ["UbuntuMono-Regular"]
Family: Verdana Font names: ["Verdana", "Verdana-Italic", "Verdana-Bold", "Verdana-BoldItalic"]
Family: Victor Mono Font names: ["VictorMono-Regular"]
...

// prints when I set a font: 

Set font to Trebuchet
Corresponding font name: Optional("TrebuchetMS") // Not applied outside of settings menu


Set font to JetBrains Mono
Corresponding font name: Optional("JetBrainsMono-Regular") // works as expected

Set font to Roboto
Corresponding font name: Optional("RobotoMono-Regular") // not applied outside of settings menu

Latest articles

spot_imgspot_img

Related articles

Leave a reply

Please enter your comment!
Please enter your name here

spot_imgspot_img