如何在 iOS 9 上的 UILabel 中获取等宽数字
How to get monospaced numbers in UILabel on iOS 9
At WWDC 2015, there was a session about the new “San Francisco” system font in iOS 9。当链接到 iOS 9 SDK 时,它默认使用比例数字渲染而不是等宽数字。 NSFont 上有一个方便的初始化程序,称为 NSFont.monospacedDigitsSystemFontOfSize(mySize weight:)
,可用于显式启用等宽数字显示。
但是我在 UIFont
上找不到 UIKit
的等价物。
方便的 UIFont
分机:
extension UIFont {
var monospacedDigitFont: UIFont {
let newFontDescriptor = fontDescriptor.monospacedDigitFontDescriptor
return UIFont(descriptor: newFontDescriptor, size: 0)
}
}
private extension UIFontDescriptor {
var monospacedDigitFontDescriptor: UIFontDescriptor {
let fontDescriptorFeatureSettings = [[UIFontDescriptor.FeatureKey.featureIdentifier: kNumberSpacingType,
UIFontDescriptor.FeatureKey.typeIdentifier: kMonospacedNumbersSelector]]
let fontDescriptorAttributes = [UIFontDescriptor.AttributeName.featureSettings: fontDescriptorFeatureSettings]
let fontDescriptor = self.addingAttributes(fontDescriptorAttributes)
return fontDescriptor
}
}
@IBOutlet
属性的用法:
@IBOutlet private var timeLabel: UILabel? {
didSet {
timeLabel.font = timeLabel.font.monospacedDigitFont
}
}
最新版本 GitHub。
从 iOS 9:
开始,现在可以在 UIFont
中使用
+ (UIFont *)monospacedDigitSystemFontOfSize:(CGFloat)fontSize weight:(CGFloat)weight NS_AVAILABLE_IOS(9_0);
例如:
[UIFont monospacedDigitSystemFontOfSize:42.0 weight:UIFontWeightMedium];
或 Swift:
UIFont.monospacedDigitSystemFont(ofSize: 42.0, weight: UIFontWeightMedium)
@Rudolf Adamkovic 代码的一点改进版本,它检查 iOS 版本:
var monospacedDigitFont: UIFont {
if #available(iOS 9, *) {
let oldFontDescriptor = fontDescriptor()
let newFontDescriptor = oldFontDescriptor.monospacedDigitFontDescriptor
return UIFont(descriptor: newFontDescriptor, size: 0)
} else {
return self
}
}
注意:目前接受的答案中的方法在 Xcode 7.3 (Swift 2.2) 中开始崩溃,仅在发布版本中。消除中间 monospacedDigitFontDescriptor
扩展变量解决了这个问题。
extension UIFont {
var monospacedDigitFont: UIFont {
let fontDescriptorFeatureSettings = [[UIFontFeatureTypeIdentifierKey: kNumberSpacingType, UIFontFeatureSelectorIdentifierKey: kMonospacedNumbersSelector]]
let fontDescriptorAttributes = [UIFontDescriptorFeatureSettingsAttribute: fontDescriptorFeatureSettings]
let oldFontDescriptor = fontDescriptor()
let newFontDescriptor = oldFontDescriptor.fontDescriptorByAddingAttributes(fontDescriptorAttributes)
return UIFont(descriptor: newFontDescriptor, size: 0)
}
}
或者,只使用 Helvetica。它仍然有等宽数字并且可以追溯到旧的 iOS 版本。
已接受的解决方案效果很好,但在将编译器优化设置为快速(发布版本的默认设置)时崩溃。像这样重写了代码,现在没有了:
extension UIFont
{
var monospacedDigitFont: UIFont
{
return UIFont(descriptor: fontDescriptor().fontDescriptorByAddingAttributes([UIFontDescriptorFeatureSettingsAttribute: [[UIFontFeatureTypeIdentifierKey: kNumberSpacingType, UIFontFeatureSelectorIdentifierKey: kMonospacedNumbersSelector]]]), size: 0)
}
}
在 Swift 4 中进行了相当多的重命名,因此属性现在如下所示:
let fontDescriptorAttributes = [
UIFontDescriptor.AttributeName.featureSettings: [
[
UIFontDescriptor.FeatureKey.featureIdentifier: kNumberSpacingType,
UIFontDescriptor.FeatureKey.typeIdentifier: kMonospacedNumbersSelector
]
]
]
Swift 5.2 使用动态类型 之后的示例用法。
label.font = .init(descriptor: UIFont.preferredFont(forTextStyle: .body)
.fontDescriptor.addingAttributes([
.featureSettings: [[
UIFontDescriptor.FeatureKey.featureIdentifier: kNumberSpacingType,
.typeIdentifier: kMonospacedNumbersSelector]]]),
size: 0)
值得一提的 macOS (AppKit) 略有不同:
NSFont(descriptor: NSFont.systemFont(ofSize: 20).fontDescriptor
.addingAttributes([.featureSettings: [[NSFontDescriptor.FeatureKey
.selectorIdentifier: kMonospacedNumbersSelector,
.typeIdentifier: kNumberSpacingType]]]), size: 0)
At WWDC 2015, there was a session about the new “San Francisco” system font in iOS 9。当链接到 iOS 9 SDK 时,它默认使用比例数字渲染而不是等宽数字。 NSFont 上有一个方便的初始化程序,称为 NSFont.monospacedDigitsSystemFontOfSize(mySize weight:)
,可用于显式启用等宽数字显示。
但是我在 UIFont
上找不到 UIKit
的等价物。
方便的 UIFont
分机:
extension UIFont {
var monospacedDigitFont: UIFont {
let newFontDescriptor = fontDescriptor.monospacedDigitFontDescriptor
return UIFont(descriptor: newFontDescriptor, size: 0)
}
}
private extension UIFontDescriptor {
var monospacedDigitFontDescriptor: UIFontDescriptor {
let fontDescriptorFeatureSettings = [[UIFontDescriptor.FeatureKey.featureIdentifier: kNumberSpacingType,
UIFontDescriptor.FeatureKey.typeIdentifier: kMonospacedNumbersSelector]]
let fontDescriptorAttributes = [UIFontDescriptor.AttributeName.featureSettings: fontDescriptorFeatureSettings]
let fontDescriptor = self.addingAttributes(fontDescriptorAttributes)
return fontDescriptor
}
}
@IBOutlet
属性的用法:
@IBOutlet private var timeLabel: UILabel? {
didSet {
timeLabel.font = timeLabel.font.monospacedDigitFont
}
}
最新版本 GitHub。
从 iOS 9:
开始,现在可以在UIFont
中使用
+ (UIFont *)monospacedDigitSystemFontOfSize:(CGFloat)fontSize weight:(CGFloat)weight NS_AVAILABLE_IOS(9_0);
例如:
[UIFont monospacedDigitSystemFontOfSize:42.0 weight:UIFontWeightMedium];
或 Swift:
UIFont.monospacedDigitSystemFont(ofSize: 42.0, weight: UIFontWeightMedium)
@Rudolf Adamkovic 代码的一点改进版本,它检查 iOS 版本:
var monospacedDigitFont: UIFont {
if #available(iOS 9, *) {
let oldFontDescriptor = fontDescriptor()
let newFontDescriptor = oldFontDescriptor.monospacedDigitFontDescriptor
return UIFont(descriptor: newFontDescriptor, size: 0)
} else {
return self
}
}
注意:目前接受的答案中的方法在 Xcode 7.3 (Swift 2.2) 中开始崩溃,仅在发布版本中。消除中间 monospacedDigitFontDescriptor
扩展变量解决了这个问题。
extension UIFont {
var monospacedDigitFont: UIFont {
let fontDescriptorFeatureSettings = [[UIFontFeatureTypeIdentifierKey: kNumberSpacingType, UIFontFeatureSelectorIdentifierKey: kMonospacedNumbersSelector]]
let fontDescriptorAttributes = [UIFontDescriptorFeatureSettingsAttribute: fontDescriptorFeatureSettings]
let oldFontDescriptor = fontDescriptor()
let newFontDescriptor = oldFontDescriptor.fontDescriptorByAddingAttributes(fontDescriptorAttributes)
return UIFont(descriptor: newFontDescriptor, size: 0)
}
}
或者,只使用 Helvetica。它仍然有等宽数字并且可以追溯到旧的 iOS 版本。
已接受的解决方案效果很好,但在将编译器优化设置为快速(发布版本的默认设置)时崩溃。像这样重写了代码,现在没有了:
extension UIFont
{
var monospacedDigitFont: UIFont
{
return UIFont(descriptor: fontDescriptor().fontDescriptorByAddingAttributes([UIFontDescriptorFeatureSettingsAttribute: [[UIFontFeatureTypeIdentifierKey: kNumberSpacingType, UIFontFeatureSelectorIdentifierKey: kMonospacedNumbersSelector]]]), size: 0)
}
}
在 Swift 4 中进行了相当多的重命名,因此属性现在如下所示:
let fontDescriptorAttributes = [
UIFontDescriptor.AttributeName.featureSettings: [
[
UIFontDescriptor.FeatureKey.featureIdentifier: kNumberSpacingType,
UIFontDescriptor.FeatureKey.typeIdentifier: kMonospacedNumbersSelector
]
]
]
Swift 5.2 使用动态类型
label.font = .init(descriptor: UIFont.preferredFont(forTextStyle: .body)
.fontDescriptor.addingAttributes([
.featureSettings: [[
UIFontDescriptor.FeatureKey.featureIdentifier: kNumberSpacingType,
.typeIdentifier: kMonospacedNumbersSelector]]]),
size: 0)
值得一提的 macOS (AppKit) 略有不同:
NSFont(descriptor: NSFont.systemFont(ofSize: 20).fontDescriptor
.addingAttributes([.featureSettings: [[NSFontDescriptor.FeatureKey
.selectorIdentifier: kMonospacedNumbersSelector,
.typeIdentifier: kNumberSpacingType]]]), size: 0)