SwiftUI - 用多种样式覆盖系统字体

jch*_*tel 3 fonts ios swift swiftui

所以 SwiftUI 给了我们一个很好的.font()扩展,让我们可以设置文本的字体大小、样式、粗细等。这很好地反映了 CSS 的字体属性,甚至还带有很好的速记,如.font(.title), .font(.body), .font(.caption)

CSS 在自定义字体方面大放异彩,它允许我们从一个或多个文件中导入字体,这些文件共同定义了同一系列中的多个粗细和样式。然后,您可以通过在文档的顶层声明字体系列来自动在任何地方使用该字体,然后所有字体声明将自动使用该字体。

iOS 允许我们导入自定义字体,但在使用它们时似乎不足。我正在为 iOS 寻找一种方式来反映 CSS 的行为。

我有 10 个用于单个字体系列的字体文件:5 种不同的粗细(浅色、常规、半粗体、粗体和超粗体),每个都有常规和斜体样式。我能够UIFont为这些字体实例化s,但我正在寻找一种方法来全局设置这个字体系列,以便我可以声明.font(.title, weight: .bold)并让它隐式使用我的字体系列的粗体变体和title大小。

我知道全局覆盖字体的方法,但我专门寻找一种方法来使用来自同一系列的多种字体来具有自动粗体和斜体功能。如果有一种很好的 SwiftUI 方式来做到这一点,那将是首选,但 UIKit 解决方案也很好。

编辑:我应该提到的另一件事是,View即使没有.font()修饰符,我也希望每个的默认字体都使用我的字体。所以如果我有

Text("Hello, world")
Run Code Online (Sandbox Code Playgroud)

它应该使用我的字体和默认的粗细和大小(我认为这是.body)。

LuL*_*aGa 8

您可以开始定义自定义ViewModifier来处理选择正确的字体类型和大小的逻辑:

struct MyFont: ViewModifier {
    
    @Environment(\.sizeCategory) var sizeCategory
    
    public enum TextStyle {
        case title
        case body
        case price
    }
    
    var textStyle: TextStyle

    func body(content: Content) -> some View {
       let scaledSize = UIFontMetrics.default.scaledValue(for: size)
       return content.font(.custom(fontName, size: scaledSize))
    }
    
    private var fontName: String {
        switch textStyle {
        case .title:
            return "TitleFont-oBld"
        case .body:
            return "MyCustomFont-Regular"
        case .price:
            return "MyCustomFont-Mono"
        }
    }
    
    private var size: CGFloat {
        switch textStyle {
        case .title:
            return 26
        case .body:
            return 16
        case .price:
            return 14
        }
    }
    
}
Run Code Online (Sandbox Code Playgroud)

在它里面,你为你想要在你的应用程序中重用的所有文本样式定义一个枚举。您可以使用与 native 相同的名称,Font.TextStyle例如.title.body或定义您自己的名称,例如.price在上面的示例中。

对于每种情况,TextStyle您都必须声明字体的名称及其默认大小。如果你sizeCategory在我的例子中包括字体将适应动态类型。

您还可以定义一个扩展,View以便能够以与本机font(_ font: Font?).

extension View {
    
    func myFont(_ textStyle: MyFont.TextStyle) -> some View {
        self.modifier(MyFont(textStyle: textStyle))
    }
}
Run Code Online (Sandbox Code Playgroud)

现在你可以像这样应用它:

Text("Any text will do").myFont(.title)
Text("£3.99").myFont(.price)
Run Code Online (Sandbox Code Playgroud)

对于Text没有应用修饰符的默认值,您可以使用 Mahdi BM 的解决方案或定义您自己的类型:

struct MyText: View {
    
    let text: String
    
    init(_ text: String) {
        self.text = text
    }
    
    var body: some View {
        Text(text).myFont(.body)
    }
    
}
Run Code Online (Sandbox Code Playgroud)


Mah*_* BM 6

.environment()您可以通过在视图顶部使用修饰符来覆盖系统的默认环境字体。您可以在第一个视图之上使用它,这样它将应用于您的所有视图。

.environment(\.font, .custom("Your_Font_Name", size: theFontSizeYouPrefer))
Run Code Online (Sandbox Code Playgroud)