SwiftUI 小技巧:如何读取 SwiftUI Font 的详细信息

0 阅读4分钟

SwiftUI 小技巧:如何读取 SwiftUI Font 的详细信息

Snipaste_2026-09-20_17-44-41.webp

字号、字体名称、粗体、斜体等属性,都能拿到

我见过不少开发者,甚至一些 AI 工具都说:我们无法从 SwiftUI 的 Font 中获取任何具体信息。在此之前,我也一直是这么认为的。

但今天,我突然非常需要读取字体信息,主要是字体名称、字号,以及是否为粗体或斜体。

我的应用是多平台项目,所以我实在不想为此退回 UIKit。如果使用 UIFont,到了 macOS 上又要通过 #if os(macOS) 切换成对应的 NSFont,还得额外维护一套平台判断。

与其花时间写这段条件编译,我决定对 Font 按下 Command + Click,顺着定义一路查看它公开的 API。

结果还真让我发现了一个很实用的方法。

使用 resolve(in:)

这个方法就是 resolve(in:)

它适用于 iOS 26、iPadOS 26、macOS 26、Mac Catalyst 26、tvOS 26、watchOS 26 和 visionOS 26 及以上系统,返回一个 Font.Resolved 实例。

我之前知道 Colorresolve 方法,现在发现字体也有对应能力,确实很方便。

Font.Resolved 提供了不少可以直接读取的属性,例如:

更重要的是,我们还能拿到 ctFont

前面列出的属性,可以看作 SwiftUI 帮我们从 CTFont 中整理出的常用信息。拿到 ctFont 后,还能继续通过 Core Text API 获取更多内容。

例如,可以使用 CTFontCopyFullName 获取字体的完整名称,或者用 CTFontCopyCharacterSet 获取该字体支持的 Unicode 字符集合。熟悉 Core Text 的开发者应该知道,CTFont 能提供的信息非常丰富。

使用示例

调用 resolve(in:) 时,需要传入一个 Font.Context。这个 Context 从哪里来?答案还是我们熟悉的 EnvironmentValues

可以通过 fontResolutionContext 从 Environment 中读取:

struct FontAttributeDemo: View {
    @Environment(\.fontResolutionContext) private var fontContext

    var body: some View {
        List {
            // 从 SwiftUI Font 中读取属性:
            // 1. 通过 EnvironmentValues/fontResolutionContext 获取 Font.Context
            // 2. 调用 font.resolve(in:)
            let font = Font.system(size: 12, weight: .bold, design: .monospaced)
                .bold().italic()
            let resolved = font.resolve(in: self.fontContext)

            Section {
                // 还可以读取其他 CTFont 属性,
                // 例如本地化名称、支持的字符集合等。
                LabeledContent(
                    "字体名称",
                    value: CTFontCopyFullName(resolved.ctFont) as String
                )
                LabeledContent("字号", value: "\(resolved.pointSize)")
                LabeledContent("字重", value: "\(resolved.weight)")
                LabeledContent("是否为粗体", value: "\(resolved.isBold)")
                LabeledContent("是否为斜体", value: "\(resolved.isItalic)")
                LabeledContent("字宽", value: "\(resolved.width)")
                LabeledContent("行间距", value: "\(resolved.leading)")
                LabeledContent("是否为等宽字体", value: "\(resolved.isMonospaced)")
                LabeledContent(
                    "是否使用小型大写字母显示小写字符",
                    value: "\(resolved.isLowercaseSmallCaps)"
                )
                LabeledContent(
                    "是否使用小型大写字母显示大写字符",
                    value: "\(resolved.isUppercaseSmallCaps)"
                )
                LabeledContent("是否使用小型大写字母", value: "\(resolved.isSmallCaps)")
            } header: {
                Text("Font.system(size: 12, weight: .bold, design: .monospaced).bold().italic()")
                    .font(.caption)
                    .fontWeight(.semibold)
            }
        }
    }
}

这里的关键步骤只有两个:

  1. 使用 @Environment(\.fontResolutionContext) 获取当前环境中的字体解析上下文。
  2. 调用 font.resolve(in: fontContext),得到 Font.Resolved

为什么需要 Context?因为 SwiftUI 的 Font 不一定代表一套固定不变的字体参数。像 Dynamic Type、平台环境和字体配置等因素,都可能影响它最终解析出来的结果。因此,resolve(in:) 需要结合当前环境,给出实际生效的字体信息。

这也意味着:如果你要观察用户调整文字大小后的结果,应该在对应 View 的 Environment 中重新解析,而不是把某一次得到的 Font.Resolved 当成永久不变的数据。

其他支持 resolve 的 SwiftUI 类型

除了 Font,SwiftUI 中还有其他类型提供类似的 resolve 方法,例如:

当你需要知道某个 SwiftUI 抽象值在当前环境中最终会呈现为什么具体结果时,可以先看看对应类型是否提供了 resolve API。

最后说两句

以前,如果想从 SwiftUI 的 Font 中读取具体属性,往往要借助 UIFontNSFont。从 iOS 26 开始,Font.resolve(in:) 为多平台 SwiftUI 项目提供了一套更直接、更统一的方案。

它既能快速读取字号、字重、粗体和斜体等常用属性,也能通过 ctFont 继续访问 Core Text 提供的完整字体信息。

如果你的应用仍需支持 iOS 26 之前的系统,就要通过可用性判断隔离这段代码,并为旧系统保留兼容方案。


我是小侯爷。 在帝都北京工作,喜欢iOS、Flutter、Android、React。 最近打算跳槽,正在找新的工作,欢迎大家给内推哦。 如果读完觉得有收获的话,记得点赞哦