11

I'm trying to set a custom default font in my SwiftUI app. I tried several suggestions from this thread Set a default font for whole iOS app?.

However, none of those seem to work with SwiftUI. For example with this approach:

// Constants.swift
struct Fonts {
    static var plex = "IBMPlexMono-Text"
}


// FontExtension.swift
extension UILabel {
    var substituteFontName : String {
        get { return self.font.fontName }
        set { self.font = UIFont(name: Fonts.plex, size: 17)! }
    }

}

// AppDelegate.swift in didFinishLaunchingWithOptions-function
UILabel.appearance().substituteFontName = Fonts.plex

When I start the app, the custom font appears for a split second and then changes back to the default font by Apple. Why does it change back to Apple's font and how can it be done permanently?

Is it maybe possible with an extension on Text-View?

simibac
  • 7,672
  • 3
  • 36
  • 48
  • it has a .font(). // font(Font(CTFont)) declaration – E.Coms Nov 13 '19 at 18:02
  • 1
    Try approach from my answer for [this post](https://stackoverflow.com/questions/58790343/set-system-to-always-use-rounded-font/58790773#58790773) – Asperi Nov 13 '19 at 18:31
  • @Asperi thank you for the link. The proposed solution is very simple and effective. However, it does not change all the `Text` Views to a new font. For example the title in the navigationbar is not updated with the new font. – simibac Nov 14 '19 at 12:41
  • 1
    NavigationView, actually, is a special case, for now it can be configured only via UINavigationBar.appearance(). Eg. for font is `UINavigationBar.appearance().largeTitleTextAttributes = [.font: UIFont(name: "Arial", size: 32)!]` – Asperi Nov 14 '19 at 13:16
  • 1
    Okay thanks, that works for the large titles. And for the inline titles I use `UINavigationBar.appearance().titleTextAttributes = [.font : UIFont(name: Fonts.plexSemiBold, size: 20)!]` And for the back Buttons I guess I use `.navigationBarBackButtonHidden(true)` and implement a custom `NavigationBarItem`. Then all the text should be updated. Kinda of a pain but it works. – simibac Nov 14 '19 at 13:24

3 Answers3

1

You can have:

extension Font {
    static let mediumFont = Font.custom("Sans-Regular", size: Font.TextStyle.subheadline.size, relativeTo: .caption)
    static let mediumSmallFont = Font.custom("Sans-Regular", size: Font.TextStyle.footnote.size, relativeTo: .caption)
    static let smallFont = Font.custom("Sans-Regular", size: Font.TextStyle.caption.size, relativeTo: .caption)
    static let verySmallFont = Font.custom("Sans-Regular", size: Font.TextStyle.caption2.size, relativeTo: .caption)
}

extension Font.TextStyle {
    var size: CGFloat {
        switch self {
        case .largeTitle: return 60
        case .title: return 48
        case .title2: return 34
        case .title3: return 24
        case .headline, .body: return 18
        case .subheadline, .callout: return 16
        case .footnote: return 14
        case .caption: return 12
        case .caption2: return 10
        @unknown default:
            return 8
        }
    }
}

and use it like this:

Text("Edit Profile")
   .font(.mediumSmallFont)
Edi
  • 1,900
  • 18
  • 27
1

this is the closest I could find to have a self-contained swift file that will change the font everywhere. make sure to call Font.setup in the app delegate on launch:

//
//  Font.swift
//  Hockey
//
//  Created by @yspreen on 11/11/22.
//

import SwiftUI

extension Font {
    static var brand = Font
        .custom("Some Font", size: UIFont.preferredFont(
            forTextStyle: .body
        ).pointSize)

    static func setUp() {
        let appearance = UINavigationBar.appearance()
        let largeTitle = UIFont.preferredFont(
            forTextStyle: .largeTitle
        ).pointSize
        let body = UIFont.preferredFont(
            forTextStyle: .body
        ).pointSize
        let caption1 = UIFont.preferredFont(
            forTextStyle: .caption1
        ).pointSize

        print(UIFont.preferredFont(forTextStyle: .largeTitle))
        appearance.largeTitleTextAttributes = [
            .font : UIFont(
                name: "SomeFont-Bold", size: largeTitle
            )!
        ]
        appearance.titleTextAttributes = [
            .font : UIFont(
                name: "SomeFont-Medium", size: body
            )!
        ]

        UITabBarItem.appearance().setTitleTextAttributes([.font: UIFont(name: "SomeFont-Regular", size: caption1)!], for: .normal)
        UITabBarItem.appearance().setTitleTextAttributes([.font: UIFont(name: "SomeFont-Regular", size: caption1)!], for: .selected)
    }
}

func Text(_ content: any StringProtocol) -> SwiftUI.Text {
    .init(content).font(.brand)
}

func TextField(_ titleKey: LocalizedStringKey, text: Binding<String>, axis: Axis = .horizontal) -> some View {
    SwiftUI.TextField(titleKey, text: text, axis: axis).font(.brand)
}


yspreen
  • 1,759
  • 2
  • 20
  • 44
  • Any idea how this would be applied to a SwiftUI Label(…)? – DeveloBär Feb 27 '23 at 19:49
  • 1
    hey @DeveloBär (great name btw) you can just copy the method in a similar manner with the signature `func Label(_ titleKey: LocalizedStringKey, image name: String) -> SwiftUI.Label { .init( ... ) }` – yspreen Feb 27 '23 at 21:25
-1

You can use a custom font like this:

Font.custom("Font-Family-Name", size: fontSize)

Example:

Text("Testing")
.font(Font.custom("Font-Family-Name", size: 16))

For using the font anywhere in the app, create a structure with as follows. Be sure to import SwiftUI in the file that will contain the font structure as:

import SwiftUI

struct AppFont {
    static func commonFont(fontSize: CGFloat) -> Font {
        return Font.custom("Font-Family-Name", size: fontSize)
    }
}

Now you can use them anywhere in the app like this:

Text("Testing")
.font(AppFont.commonFont(fontSize: 16))
Shivani Bajaj
  • 996
  • 10
  • 23