ScaledFont - 使用动态类型的自定义字体

一个实用工具类型,帮助您将自定义字体与动态类型一起使用。

动态类型是一项重要的 iOS 功能,允许用户选择他们偏好的文本大小。要使用自定义字体完全支持动态类型,需要做到两件事

  1. 为每种可能的文本样式在 Large(默认)内容大小下定义一个具有合适字体粗细和大小的基础字体。
  2. 在动态类型内容大小的范围内缩放基础字体。

对于第一步,您可能需要从 Apple iOS 人机界面指南 的排版部分开始,其中列出了 Apple 为默认 San Francisco 字体使用的字体指标。

例如,在这里我创建了一个 17 磅的粗体 Noteworthy 字体作为基础标题字体,以及该字体的细体版本作为基础正文字体

let headlineFont = UIFont(name: "Noteworthy-Bold", size: 17)
let bodyFont = UIFont(name: "Noteworthy-Light", size: 17)

对于第二步,自 iOS 11 以来,已经可以使用字体指标来缩放基础字体以适应用户选择的动态类型大小

let headMetrics = UIFontMetrics(forTextStyle: .headline)
headlineLabel.font = headMetrics.scaledFont(for: headlineFont)

let bodyMetrics = UIFontMetrics(forTextStyle: .body)
bodyLabel.font = bodyMetrics.scaledFont(for: bodyFont)

问题是,如果您对您使用的每种文本样式都这样做,最终会导致这些字体指标分散在您的应用程序各处。这既难以维护,也难以在您想要进行设计更改时保持一致性。

提示:当使用 UIKit 标签、文本字段和文本视图时,不要忘记启用自动调整,以便在用户更改其偏好的内容大小时进行调整

label.adjustsFontForContentSizeCategory = true

样式字典

为了更轻松地管理所有可能的文本样式的基础字体指标,ScaledFont 类型将它们收集到一个样式字典中。您将样式字典存储为属性列表文件,默认情况下,您将其包含在主 bundle 中。

样式字典包含每个文本样式的条目。可用的文本样式有

每个条目的值是一个包含两个键的字典

例如,要在 .large 内容大小下为 .headline 样式使用 17 磅的 Noteworthy-Bold 字体

<dict>
  <key>headline</key>
  <dict>
    <key>fontName</key>
    <string>Noteworthy-Bold</string>
    <key>fontSize</key>
    <integer>17</integer>
  </dict>
</dict>

您不需要为每个文本样式都包含一个条目,但是如果您尝试使用字典中未包含的文本样式,它将回退到系统首选字体。

如果您不确定要使用什么字体名称,您可以使用此代码片段打印所有可用的名称

let families = UIFont.familyNames
families.sorted().forEach {
  print("\($0)")
  let names = UIFont.fontNames(forFamilyName: $0)
  print(names)
}

示例样式字典

请参阅此软件包中包含的 Examples 文件夹中的一些示例。Noteworthy 样式字典使用内置的 iOS 字体。

要使用 NotoSerif 示例,您需要从 Google 字体 下载字体文件,将它们添加到您的应用程序目标,并在目标的 Info.plist 文件中的“Fonts provided by application”下列表它们。

检查您计划随应用程序一起发布的任何字体的许可证。

使用 ScaledFont - UIKit

当使用 UIKit 时,您可以在代码中将缩放字体应用于文本标签、文本字段或文本视图。您需要最低部署目标为 iOS 11 或更高版本。

  1. 通过指定样式字典的名称来创建 ScaledFont。将样式字典与您正在使用的任何自定义字体一起添加到主 bundle 中

    let scaledFont = ScaledFont(fontName: "Noteworthy")
  2. 在设置任何文本标签、字段或视图的字体时,使用缩放字体的 font(forTextStyle:) 方法

    let label = UILabel()
    label.font = scaledFont.font(forTextStyle: .headline)
  3. 请记住设置 adjustsFontFotContentSizeCategory 属性,以便在用户更改其首选内容大小时自动调整字体大小

    label.adjustsFontForContentSizeCategory = true

使用 ScaledFont - SwiftUI

当使用 SwiftUI 时,您创建缩放字体并将其添加到视图的环境中。然后,您可以使用视图修饰符将缩放字体应用于视图层次结构中的任何视图。您需要最低部署目标为 iOS 13 或更高版本才能使用 SwiftUI。

  1. 通过指定样式字典的名称来创建 ScaledFont。将样式字典与您正在使用的任何自定义字体一起添加到主 bundle 中

    let scaledFont = ScaledFont(fontName: "Noteworthy")
  2. 将缩放字体应用于视图的环境。这通常可能是您的视图层次结构的根视图

    ContentView()
    .environment(\.scaledFont, scaledFont)
  3. 将缩放字体视图修饰符应用于视图层次结构中包含文本的视图

    Text("Headline")
    .scaledFont(.headline)

注意:在 sheet 中呈现的 SwiftUI 视图不会继承呈现视图的环境。如果您想在呈现的视图中使用缩放字体,您需要将其传递到环境中

struct ContentView: View {
  @Environment(\.scaledFont) private var scaledFont
  @State private var isShowingSheet = false
  
  var body: some View {
    Button("Present View") {
        isShowingSheet = true
    }
    .sheet(isPresented: $isShowingSheet) {
        SheetView()
        .environment(\.scaledFont, scaledFont)
    }
  }
}

延伸阅读

以下 useyourloaf.com 上的博客文章提供了更多详细信息