A quick tip for displaying digits with a fixed-width, monospace font, when you don’t want a “computer style” typeface.
Monospaced fonts
I want to display the hour, minute and seconds of some timers. Using the standard system font the digits have proportional spacing so they don’t vertically align and jump around as the digits change:
There are a few ways to tell SwiftUI to use a fixed width font. For example, with a fixed size system font use the system(size:weight:design:)
method. For dynamic type styles use the similar system(_:design:)
method. Either way choose a .monospaced
design:
VStack {
Text("12:34:56")
Text("07:18:19")
}
.font(.system(size: 72, weight: .regular, design: .monospaced))
The UIKit equivalent has the same effect:
timerLabel.font = UIFont.monospacedSystemFont(ofSize: 72,
weight: .regular)
That uses the SF Mono typeface from the system San Francisco font family and gives a computer text appearance to the digits. This adds a noticeable foot to the digit one, an open digit four, sixes and nines with straighter tails, and a slashed zero:
This computer style typeface isn’t always what I want. Compare SF mono to the appearance of the stopwatch timer in Apple’s Clock app:
The digits still have a fixed width but it’s using the standard San Francisco font (compare the “0”, “1”, “4” and “9” with the previous example). If you look closely you can also see that the “:” and “.” separators are not using a fixed width. This gives a different feel to the timer whilst still maintaining an overall fixed width.
How can we apply that same design to our view?
Monospaced Digits
Browsing the SwiftUI, UIKit and AppKit documentation, it turns our there’s a method for each of those frameworks that produces a version of the system font with monospaced digits but keeps all other text proportionally spaced.
For SwiftUI, there’s the monospacedDigit()
view modifier:
VStack {
Text("12:34:56")
Text("07:18:19")
}
.font(.system(size: 72))
.monospacedDigit()
For UIKit and AppKit, you can get the same font from the monospacedDigitSystemFont(ofSize:weight:)
method of UIFont
or NSFont
.
timerLabel.font = UIFont.monospacedDigitSystemFont(ofSize: 72,
weight: .regular)
This matches the design of the stopwatch, the digits are fixed width, so they align vertically, but use the default system typeface. The proportional spacing of the “:” separators is also noticeably less than the digits: