VFont
是一个出色的库,它简化了在 iOS 项目中使用可变字体的过程。
如果您从未听说过可变字体,我建议阅读这篇由 @romashamin 撰写的文章:现实生活中的可变字体:如何使用和喜爱它们。
首先,我想知道 iOS 是否支持可变字体。现在,开发者通常使用顶层的 UIFont
类来单独处理 Light、Regular、Medium、Bold 和其他字体样式。我发现 iOS 3.2
已经添加了 VF 支持。然而,它是在 CoreText
库的 CTFont
类中使用底层代码实现的。这导致需要额外的工作才能使用 CoreText
和 UIFont
来访问可变字体。
首先,您需要将自定义可变字体添加到您的项目中。如果您从未这样做过,我建议阅读这篇教程。
❗️ 请注意,字体文件名可能与实际字体名称不同!为了获取正确的完整字体名称,请将字体文件上传到 fontgauntlet.com。
// First, you have to get information about the variable font (axes names, IDs, and allowed values). But the current axis value isn't there 🤷♂️
// Here you can face a problem, like the custom font wasn't added to the project, was added incorrectly, or font name isn't correct
let uiFont = UIFont(name: "Martian Mono", size: 16.0)!
let ctFont = CTFontCreateWithName(uiFont.fontName as CFString, 16.0, nil)
let variationAxes = CTFontCopyVariationAxes(ctFont) as! [Any] // font information with weird format 👎
// To set new values you need to know the correct axis IDs and allowed values (maxValue and minValue)
let variations = [2003265652: 600, 2003072104: 100] // 2003265652 - 'Weight'; 2003072104 - `Width`
// As we know, text elements in UIKit use the UIFont class. So, you have to create new UIFont object with new values for axes
let uiFontDescriptor = UIFontDescriptor(fontAttributes: [.name: uiFont.fontName, kCTFontVariationAttribute as UIFontDescriptor.AttributeName: variations])
let newUIFont = UIFont(descriptor: uiFontDescriptor, size: uiFont.pointSize)
// Now, you can apply the UIFont object for UI text elements
// Here you may notice the name of the new UIFont object has been changed to 'MartianMono-Regular_wght2580000_wdth640000'
let label = UILabel()
label.font = newUIFont
如果您想继续更改当前的字体对象,或者您想创建更复杂的逻辑,您需要存储 UIFont
对象。此外,您还应该解析变体轴值并存储它们。但不用担心,VFont
会为您完成这一切!
import VFont
let vFont = VFont(name: "Martian Mono", size: 16)! // UIFont like initialization
vFont.setValue(400, forAxisID: 2003265652) // setting a new value for the 'Weight' axis
let label = UILabel()
label.font = vFont.uiFont // apply the variable font for a UI text element
vFont.getAxesDescription() // get the font information with а human readable format, if you need it ✅
// override the `updated` closure to observe all font changes, if you're going to change it at runtime
vFont.updated = { uiFont in
label.font = uiFont
}
struct ContentView: View {
var body: some View {
Text("Title 1")
.font(.vFont("Martian Mono", size: 16, axisID: 2003265652, value: 450))
Text("Title 2")
.font(.vFont("Inter", size: 32, axes: [2003072104: 80, 2003265652: 490])
}
}
为什么我们使用数字 ID 而不是轴名称?好问题!但答案很简单。在底层处理可变字体的
CTFont
框架会为不同的系统语言返回不同的轴名称。这意味着只有轴数字 ID 是唯一值。如果您找到一种无论系统语言如何都能接收到英文名称的方法,我将非常感激!
File
> Swift Packages
> Add Package Dependency
https://github.com/dufflink/vfont
Up to Next Major
并指定 0.6.1
要使用 CocoaPods 将 VFont
集成到您的 Xcode 项目中,请在您的 Podfile
中指定它。
pod 'VFont'
如果您使用 UIKit
,您可以创建自己的字体类,继承 VFont
类!
import VFont
final class MartianMono: VFont {
init?(size: CGFloat) {
super.init(name: "Martian Mono", size: size)
}
var weight: CGFloat {
get {
return axes[2003265652]?.value ?? .zero
} set {
setValue(newValue, axisID: 2003265652)
}
}
var width: CGFloat {
get {
return axes[2003072104]?.value ?? .zero
} set {
setValue(newValue, axisID: 2003072104)
}
}
}
let font = MartianMono(size: 16)
font?.weight = 300
font?.width = 90
在 SwiftUI
项目中,您可以创建一个 static method
作为 Font
结构体的扩展。
extension Font {
static func martianMono(size: CGFloat, width: CGFloat = 0, weight: CGFloat = 0) -> Font {
return .vFont("Martian Mono", size: size, axes: [
2003072104: width,
2003265652: weight
])
}
}
struct ContentView: View {
var body: some View {
Text("Hello, world!")
.font(.martianMono(size: 16, width: 300, weight: 100))
}
}
转到 Examples 并研究它是如何工作的!此外,您可以在 Xcode 中启动这些示例。为此,请克隆存储库并启动 VFont.xcworkspace
文件。
下一步是创建一个脚本,该脚本将解析 Info.plist
文件,并自动为 UIKit 生成字体类,并为 SwiftUI 生成扩展。生成的代码将具有与 字体类 部分中相同的结构。
支持 tvOS、watchOS 和 macOS
VFont 在 MIT 许可证下发布。查看 LICENSE 了解详情。