在2015年的WWDC上,有关于iOS 9中新的“旧金山”系统字体的会议。当链接到iOS 9 SDK时,默认情况下使用比例数字渲染而不是等宽数字。在NSFont上有一个方便的初始化器,名为NSFont.monospacedDigitsSystemFontOfSize(mySize weight:)
,可用于显式启用等宽数字显示。
但是我找不到UIFont
上的相当于此的UIKit
等价物。
自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)
便利的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 上最新版本请查看此处。
这个被接受的解决方案非常好,但是当编译器优化设置为快(默认为发布版本)时会崩溃。将代码重写如下后就不会出现这种情况了:
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
]
]
]
注意:目前被接受的答案中的方法在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)
}
}
使用Swift 5.2的示例,遵循被接受的答案使用动态类型。
label.font = .init(descriptor: UIFont.preferredFont(forTextStyle: .body)
.fontDescriptor.addingAttributes([
.featureSettings: [[
UIFontDescriptor.FeatureKey.featureIdentifier: kNumberSpacingType,
.typeIdentifier: kMonospacedNumbersSelector]]]),
size: 0)
NSFont(descriptor: NSFont.systemFont(ofSize: 20).fontDescriptor
.addingAttributes([.featureSettings: [[NSFontDescriptor.FeatureKey
.selectorIdentifier: kMonospacedNumbersSelector,
.typeIdentifier: kNumberSpacingType]]]), size: 0)
这是一个稍微改进的@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
}
}
monospacedDigitFontDescriptor
属于系统API。 - OgreSwamp或者,只需使用Helvetica字体。它仍然具有等宽数字,并且可以向旧版iOS版本回溯。
var fontDescriptor = UIFontDescriptor().fontDescriptorWithSymbolicTraits(.TraitMonoSpace)
- Felix