At WWDC 2015, there was a session about the new “San Francisco” system font in iOS 9. It uses proportional number rendering instead of monospaced numbers by default when lin
There has been quite some renaming in Swift 4, so the attributes now looks like this:
let fontDescriptorAttributes = [
UIFontDescriptor.AttributeName.featureSettings: [
[
UIFontDescriptor.FeatureKey.featureIdentifier: kNumberSpacingType,
UIFontDescriptor.FeatureKey.typeIdentifier: kMonospacedNumbersSelector
]
]
]
Example usage for Swift 5.2 following the accepted answer using dynamic type.
label.font = .init(descriptor: UIFont.preferredFont(forTextStyle: .body)
.fontDescriptor.addingAttributes([
.featureSettings: [[
UIFontDescriptor.FeatureKey.featureIdentifier: kNumberSpacingType,
.typeIdentifier: kMonospacedNumbersSelector]]]),
size: 0)
Worth mentioning for macOS (AppKit) it is slightly different:
NSFont(descriptor: NSFont.systemFont(ofSize: 20).fontDescriptor
.addingAttributes([.featureSettings: [[NSFontDescriptor.FeatureKey
.selectorIdentifier: kMonospacedNumbersSelector,
.typeIdentifier: kNumberSpacingType]]]), size: 0)
Or, just use Helvetica. It still has monospaced numbers and works retroactively to older iOS version.
Note: The method in the currently accepted answer has started crashing for me in Xcode 7.3 (Swift 2.2), only in Release builds. Eliminating the intermediary monospacedDigitFontDescriptor
extension variable fixes the issue.
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)
}
}
Handy UIFont
extension:
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
}
}
Usage with @IBOutlet
properties:
@IBOutlet private var timeLabel: UILabel? {
didSet {
timeLabel.font = timeLabel.font.monospacedDigitFont
}
}
Latest version on GitHub.
Accepted solution works great, but was crashing with compiler optimization set to Fast(default for Release builds). Rewrote the code like this and now it does not:
extension UIFont
{
var monospacedDigitFont: UIFont
{
return UIFont(descriptor: fontDescriptor().fontDescriptorByAddingAttributes([UIFontDescriptorFeatureSettingsAttribute: [[UIFontFeatureTypeIdentifierKey: kNumberSpacingType, UIFontFeatureSelectorIdentifierKey: kMonospacedNumbersSelector]]]), size: 0)
}
}