如何在SwiftUI中将自定义字体族设置为整个应用的默认字体?

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

例如:

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

它们都为默认的Helvetica字体系列指定了不同的字体样式。我想在不使用Helvetica的情况下使用这些非常有用的便利访问器。我可以改变默认的字体系列吗?还是我必须不断地应用自定义字体,例如:

Text("自定义文本").font(Font.custom("SourceSansPro-Regular", size: 14.0)

4个回答

22

如果您希望的话,可以覆盖系统字体。

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

3
这会导致在Xcode 11.5中SwiftUI实时预览崩溃。 - scaly
3
在常规元素(如“文本”)中运行良好,但对于“Section”标题或“navigationBarTitle”则不起作用,有什么想法可以实现这一点吗? - Skoua
这会导致在 Xcode 13 中使用 Preview 时崩溃,并显示以下消息:“替换的函数 'system(size:weight:design:)' 未标记为 dynamic”。 - adamsfamily
XCode 15.0 仍然没有修复。 - undefined

10

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

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

2
这里提供一种方法,结合了一些方法,特别是Justin的方法和Brady Murphy的Medium文章。思路是创建一个字体管理器,可以并入Font扩展以覆盖默认值。但我希望有一种编译指令可以跳过Previews的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
}

2
这是我的方法:
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)
    }

}

1
我需要将自定义字体添加到info.plist文件中吗? - Shomu
是的,这是必须的。 - Md Jahirul Islam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接