• iOS开发:如何在动态字体中使用自定义字体
  • 发布于 1个月前
  • 85 热度
    0 评论
  • 耀国
  • 0 粉丝 45 篇博客
  •   
前言
作为 App 开发来说,字体在应用中扮演着至关重要的角色。一个精心选择的字体能够让你的应用在众多竞争者中脱颖而出。但是,无论你选择哪种字体,都必须确保它的核心功能——可读性。在以前,只有苹果自带的系统字体支持动态调整大小,而自定义字体则不支持。但自从 iOS 11 以来,这种情况已经改变。现在,你可以轻松地在动态字体中使用你的自定义字体。

今天就来讲讲如何在动态字体中使用自定义字体。

什么是动态字体?
苹果早在 iOS 7 时就引入了动态字体,旨在让用户选择他们偏好的文本大小以满足自身需求。在较大的文本尺寸下,各种文本样式(如 .headline, .subheadline, .body, .footnote, .caption1, .caption2, .largeTitle, .title1, .title2, .title3 和 .callout)的权重、大小和行距值可以参考苹果的人机界面指南 - 动态字体尺寸[1]。

动态字体的实现
动态字体与文本样式一起起作用,文本样式用于为每种文本大小设定缩放因子。例如,.caption2 是最小的文本样式,不会缩小到小于 11 号的大小,因为那样会很难阅读。在最小、小、中和大文本大小下,.caption2 文本样式的大小将保持在 11pt。要获取动态字体,我们可以使用 UIFont 类方法 preferredFont(forTextStyle:) 来初始化字体。
let label = UILabel()
label.font = UIFont.preferredFont(forTextStyle: .body)
label.adjustsFontForContentSizeCategory = true 
设置 adjustsFontForContentSizeCategory 为 true,可以在设备的内容大小类别更改时自动更新字体。上面的代码将返回一个苹果 San Francisco 常规字体,大小为 17(大文本尺寸下的 body 样式),以下是大文本大小上的所有文本样式的示例。

调整字体大小
可以通过以下方式更改字体大小:
1.打开系统设置 - 显示与亮度 - 文字大小。
2.通过拖动滑块调整字体大小。

调整到更大的字体
通过上边的方法调整字体到一定大小就不能再大了,其实还有办法可以调到更大:
1.打开设置 - 辅助功能 - 显示与文字大小 - 更大字体。
2.打开更大字体开关。
3.通过拖动滑块调整字体大小。

调试阶段修改文本大小
在开发阶段,还可以直接从 Xcode 调整字体。
1.点击调试栏中的图标 Environment Overrides 按钮.
2.打开 Dynamic Type 开关.
3.通过拖动滑块调整字体大小。

使用自定义字体
在 iOS 11 中,苹果引入了 UIFontMetrics,使我们的代码更简单。通过它,我们可以创建指定文本样式的 UIFontMetrics,然后将自定义字体传递给 scaledFont(for:) 方法,以获得基于自定义字体的字体对象,具有适当的样式信息,并自动缩放以匹配当前动态字体设置。
let customFont = UIFont(name: "Merriweather-Regular", size: 17)! // <1>
let label = UILabel() // 堆代码 duidaima.com
label.adjustsFontForContentSizeCategory = true
label.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: customFont) // <2>
<1> 我们初始化了自定义字体。在这个例子中,我使用了 Google 字体的 Merriweather 字体。
<2> 我们定义了 UIFontMetrics 的 body 文本样式,然后用它来缩放我们的自定义字体。

支持自定义字体的动态类型
虽然 UIFontMetrics 可以减少我们在支持动态类型的自定义字体上的工作量,但它并不是万能的。有时候我们仍然需要做一些额外的工作。
scaledFont(for:) 方法会根据大文本尺寸的基础字体大小应用缩放因子。苹果在 iOS 人机界面指南中说明了系统字体的字体度量标准。你可以用它作为为每种文本样式定义自定义字体的起始。

以下是我基于苹果度量的简单实现:
let customFonts: [UIFont.TextStyle: UIFont] = [
    .largeTitle: UIFont(name: "Merriweather-Regular", size: 34)!,
    .title1: UIFont(name: "Merriweather-Regular", size: 28)!,
    .title2: UIFont(name: "Merriweather-Regular", size: 22)!,
    .title3: UIFont(name: "Merriweather-Regular", size: 20)!,
    .headline: UIFont(name: "Merriweather-Bold", size: 17)!,
    .body: UIFont(name: "Merriweather-Regular", size: 17)!,
    .callout: UIFont(name: "Merriweather-Regular", size: 16)!,
    .subheadline: UIFont(name: "Merriweather-Regular", size: 15)!,
    .footnote: UIFont(name: "Merriweather-Regular", size: 13)!,
    .caption1: UIFont(name: "Merriweather-Regular", size: 12)!,
    .caption2: UIFont(name: "Merriweather-Regular", size: 11)!
]

extension UIFont {
    class func customFont(forTextStyle style: UIFont.TextStyle) -> UIFont {
        let customFont = customFonts[style]!
        let metrics = UIFontMetrics(forTextStyle: style)
        let scaledFont = metrics.scaledFont(for: customFont)
        
        return scaledFont
    }
}
将 UIFontMetrics(forTextStyle: style).scaledFont(for: customFont) 替换为 UIFont.customFont(forTextStyle: style) 并再次运行即可。
let styles: [UIFont.TextStyle] = [.largeTitle, .title1, .title2, .title3, .headline, .subheadline, .body, .callout, .footnote, .caption1, .caption2]
for style in styles {
    ...
    let label = UILabel()
    label.adjustsFontForContentSizeCategory = true
    label.text = String(describing: style)
    label.font = UIFont.customFont(forTextStyle: style)    
    ...
}
最后看下效果:

结论
UIFontMetrics 可以减少我们在让自定义字体支持动态类型时所需的工作量。另外我们可能需要花一些时间来微调基础字体以确保其在所有变体中都适合,在 UIFontMetrics 的帮助下,这个过程不算负责。希望这能帮助你更好地在应用中运用自定义字体。关于自定义动态字体,你有什么看法吗?欢迎在评论区中留言交流。

参考资料
[1]苹果的人机界面指南: https://developer.apple.com/design/human-interface-guidelines/typography#dynamic-type-sizes
用户评论