如何在 SwiftUI 中将自定义字体系列设置为整个应用程序的默认字体

Posted

技术标签:

【中文标题】如何在 SwiftUI 中将自定义字体系列设置为整个应用程序的默认字体【英文标题】:How to set a custom font family as the default for an entire app in SwiftUI 【发布时间】:2019-10-14 11:05:51 【问题描述】:

在 SwiftUI 中,您可以获得所有这些方便的小字体便利访问器,例如 Font.captionFont.titleFont.body 等。

例如

VStack 
 Text("Some Title").font(Font.title)
 Text("Some Caption Text").font(Font.caption)

它们都为默认的 Helvetica 字体系列指定了不同的字体样式。我想使用这些非常有用的便利访问器,而无需在我的应用程序中使用 Helvetica。 我可以更改默认字体系列吗? 或者我是否必须经常应用自定义字体,例如:

Text("Custom Text").font(Font.custom("SourceSansPro-Regular", size: 14.0)

【问题讨论】:

【参考方案1】:

您可以根据需要覆盖系统字体。

    extension Font 
    
    /// Create a font with the large title text style.
    public static var largeTitle: Font 
        return Font.custom("OpenSans-Regular", size: UIFont.preferredFont(forTextStyle: .largeTitle).pointSize)
    

    /// Create a font with the title text style.
    public static var title: Font 
        return Font.custom("OpenSans-Regular", size: UIFont.preferredFont(forTextStyle: .title1).pointSize)
    

    /// Create a font with the headline text style.
    public static var headline: Font 
        return Font.custom("OpenSans-Regular", size: UIFont.preferredFont(forTextStyle: .headline).pointSize)
    

    /// Create a font with the subheadline text style.
    public static var subheadline: Font 
        return Font.custom("OpenSans-Light", size: UIFont.preferredFont(forTextStyle: .subheadline).pointSize)
    

    /// Create a font with the body text style.
    public static var body: Font 
           return Font.custom("OpenSans-Regular", size: UIFont.preferredFont(forTextStyle: .body).pointSize)
       

    /// Create a font with the callout text style.
    public static var callout: Font 
           return Font.custom("OpenSans-Regular", size: UIFont.preferredFont(forTextStyle: .callout).pointSize)
       

    /// Create a font with the footnote text style.
    public static var footnote: Font 
           return Font.custom("OpenSans-Regular", size: UIFont.preferredFont(forTextStyle: .footnote).pointSize)
       

    /// Create a font with the caption text style.
    public static var caption: Font 
           return Font.custom("OpenSans-Regular", size: UIFont.preferredFont(forTextStyle: .caption1).pointSize)
       

    public static func system(size: CGFloat, weight: Font.Weight = .regular, design: Font.Design = .default) -> Font 
        var font = "OpenSans-Regular"
        switch weight 
        case .bold: font = "OpenSans-Bold"
        case .heavy: font = "OpenSans-ExtraBold"
        case .light: font = "OpenSans-Light"
        case .medium: font = "OpenSans-Regular"
        case .semibold: font = "OpenSans-SemiBold"
        case .thin: font = "OpenSans-Light"
        case .ultraLight: font = "OpenSans-Light"
        default: break
        
        return Font.custom(font, size: size)
    

【讨论】:

这会导致 SwiftUI 实时预览在 Xcode 11.5 中崩溃。 适用于Text 等常规元素,但不适用于Section 标头或navigationBarTitle,知道如何实现这一点吗? 这会使 Xcode 13 中的 Preview 崩溃,并显示以下消息:replaced function 'system(size:weight:design:)' is not marked dynamic【参考方案2】:

我目前的方法是重新创建自己的字体工厂:

struct MyFont 
  static let title = Font.custom("SourceSansPro-Bold", size: 24.0)
  static let body = Font.custom("SourceSansPro-Regular", size: 12.0)

然后使用例如MyFont.title 代替 Font.title

【讨论】:

【参考方案3】:

这是我的方法:

struct Fonts 

    static func oswaldRegular(size:CGFloat) -> Font
        return Font.custom("Oswald-Regular", size: size)
    

    static func oswaldLight(size:CGFloat) -> Font
        return Font.custom("Oswald-Light", size: size)
    

    static func oswaldBold(size:CGFloat) -> Font
        return Font.custom("Oswald-Bold", size: size)
    


【讨论】:

我可以在 info.plist 中添加自定义字体吗? 是的。它是假的。【参考方案4】:

这是一种结合了其中一些方法的方法,特别是 Justin 的方法和 Brady Murphy 的 Medium 文章。这个想法是创建一个字体管理器,可以合并到Font 扩展中以覆盖默认值。我希望有一个编译器指令可以跳过预览的字体扩展。这仍然会中断预览。

这个函数使用一次将获取实际的字体名称:

// put the following into the .onAppear of a top level view or App.init
func getCustomFontNames() 
    // get each of the font families
    for family in UIFont.familyNames.sorted() 
        let names = UIFont.fontNames(forFamilyName: family)
        // print array of names
        print("Family: \(family) Font names: \(names)")
    

字体管理器可以创建默认字体,但也允许通过直接调用字体系列结构来使用多种字体。

typealias FMgr = FontManager
struct FontManager 
    
    // dynamic font sizes
    struct dynamicSize 
        public static var largeTitle    : CGFloat   = UIFont.preferredFont(forTextStyle: .largeTitle).pointSize
        public static var title         : CGFloat   = UIFont.preferredFont(forTextStyle: .title1).pointSize
        // repeat for all the dynamic sizes
    
    
    // App Supplied Fonts
    struct Quicksand 
        static let familyRoot   = "Quicksand"
        
        // weights
        static let heavy        = bold
        static let bold         = "\(familyRoot)-Bold"
        static let semibold     = "\(familyRoot)-SemiBold"
        static let medium       = regular
        static let regular      = "\(familyRoot)-Regular"
        static let thin         = light
        static let light        = "\(familyRoot)-Light"
        static let ultralight   = light
        
        // dynamic sizes
        static let largeTitle   : Font = Font.custom(FMgr.Quicksand.bold, size: FMgr.dynamicSize.largeTitle)
        // repeat for other sizes
        
    

    // structs for other fonts


extension Font 
    
    public static var largeTitle = FMgr.Quicksand.largeTitle
    // repeat for the rest of the dynamic sizes

【讨论】:

以上是关于如何在 SwiftUI 中将自定义字体系列设置为整个应用程序的默认字体的主要内容,如果未能解决你的问题,请参考以下文章

如何在iOS中将具有特定大小的自定义字体设置为Web View?

如何查看 SwiftUI 可以作为自定义字体提供的其他字体选项?

如何在 swiftui 中添加自定义字体?

如何在 Xamarin 中使用 CSS 设置自定义字体系列

SwiftUI-自定义修饰符

SwiftUI一起学之五 -- 使用自定义字体