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

SwiftUI - Override the system font with multiple styles

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

这样的简写形式。

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

iOS 允许我们导入自定义字体,但在 使用 方面似乎还不够。我正在寻找一种方法让 iOS 反映 CSS 的行为。

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

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

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

Text("Hello, world")

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

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

.environment(\.font, .custom("Your_Font_Name", size: theFontSizeYouPrefer))

您可以开始定义自定义 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
        }
    }
    
}

在其中,您可以为要在应用中重复使用的所有文本样式定义一个枚举。您可以使用与本机 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))
    }
}

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

Text("Any text will do").myFont(.title)
Text("£3.99").myFont(.price)

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

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