如何在 SwiftUI 中缩放系统字体以支持动态类型?

How to scale system font in SwiftUI to support Dynamic Type?

在 UIKit 中,我可以像这样更改 UILabel 的字体大小以支持使用系统字体的动态类型:

UIFontMetrics.default.scaledFont(for: UIFont.systemFont(ofSize: 16))

我是不是弄错了,或者在 SwiftUI 中没有办法做这样的事情? 既要使用系统字体又要支持Dynamic Type,是否可以只使用默认字体样式.title等?

来自 HackingWithSwift 的

This solution 似乎只适用于自定义字体,对吧?

提前感谢您的任何建议!

以下方法有效(使用 Xcode 11.2.1 / iOS 13.2.2 测试)

var body: some View {
    Text("Hello, World!") // direct text .font
        .font(Font.system(size: UIFontMetrics.default.scaledValue(for: 16)))
}

以及基于视图的修饰符

VStack {
    Text("Hello, World!")
}
.font(Font.system(size: UIFontMetrics.default.scaledValue(for: 16)))

您可以创建一个 ViewModifier 和一个 View 扩展,就像您提到的 HackingWithSwift 文章中那样,但它使用系统字体。

struct ScaledFont: ViewModifier {
    // From the article:
    // Asks the system to provide the current size category from the
    // environment, which determines what level Dynamic Type is set to.
    // The trick is that we don’t actually use it – we don’t care what the
    // Dynamic Type setting is, but by asking the system to update us when
    // it changes our UIFontMetrics code will be run at the same time,
    // causing our font to scale correctly.
    @Environment(\.sizeCategory) var sizeCategory
    var size: CGFloat
    
    func body(content: Content) -> some View {
        let scaledSize = UIFontMetrics.default.scaledValue(for: size)
        return content.font(.system(size: scaledSize))
    }
}

extension View {
    func scaledFont(size: CGFloat) -> some View {
        return self.modifier(ScaledFont(size: size))
    }
}

用法示例:

var body: some View {
    Text("Hello, World!").scaledFont(size: 18)
}

您可以使用 Xcode 12 上的“环境覆盖”面板对其进行测试。

只要你有

@Environment(\.sizeCategory) var sizeCategory

加载文件层次结构中的某处,.font(Font.system(size: UIFontMetrics.default.scaledValue(for: 16)))会随着系统字体大小的变化而变化。

上面发布的视图修饰符@Mokkun 有效,因为它包含环境变量 sizeCategory

将环境变量 sizeCategory 放在任何 SwiftUI 视图的顶部,然后直接使用 UIFontMetrics.default.scaledValue(...) 也可以。像这样:

import SwiftUI

struct ContentViewSheet: View {

    @Environment(\.sizeCategory) var sizeCategory
    
    var body: some View {
        Text("Hello world")
            .font(Font.system(size: UIFontMetrics.default.scaledValue(for: 16)))
    }
}