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

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

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

我见过不少开发者,甚至一些 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 中读取:

swift 复制代码
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。 最近打算跳槽,正在找新的工作,欢迎大家给内推哦。 如果读完觉得有收获的话,记得点赞哦

相关推荐
李游Leo2 小时前
HarmonyOS 7 实战开发 05:把页面做到可上线状态
ios·harmonyos
终端安全笔记7 小时前
描述文件、企业证书、MDM 不是三个名字,是三层
android·ios·智能手机
传奇开心果编程8 小时前
【SwiftUI入门练中学】第1课 从零开始
学习·ui·ios·swiftui·swift
丿Wayne14 小时前
iOS Token 刷新实战(Actor 避免并发重复刷新)
ios·swift·token·actor·swift并发
终端安全笔记1 天前
iOS 27 给了租赁一个新工具,但它只认受监督的设备
android·网络·安全·ios
大熊猫侯佩1 天前
独立 App 首发完成 iPhone Duo 展开态适配
ios·swiftui·swift
光影少年1 天前
setImmediate 和 setTimeout(0) 的区别
android·前端·react.js·ios·前端框架
2501_916008891 天前
SSE 和 gRPC 流式接口如何抓包,调试 SSE 与 gRPC 流式接口
网络协议·计算机网络·网络安全·ios·adb·https·udp