How to stop a time UILabel from resizing at every time increment?

core-text, nsattributedstring, nsstring, objective-c, swift

Solution

Use a monospaced font or pass parameters when creating the font which force monospaced numbers:

//kNumberSpacingType 6
//kMonospacedNumbersSelector 0
NSArray *setting = @[
                         @{
                             UIFontFeatureTypeIdentifierKey: @(6),
                             UIFontFeatureSelectorIdentifierKey: @(0)
                             }
                         ];

return [UIFont fontWithDescriptor:[[self fontDescriptor] fontDescriptorByAddingAttributes:@{UIFontDescriptorFeatureSettingsAttribute : setting}] size:0.0];

Problem

I have a stopwatch feature in my app that uses a centered attributed `UILabel` with a proportionally spaced font to render time. At every time increment the width of the label changes, creating a bouncing effect that looks especially bad at fast speeds. Here is an example. How can I fix this? iOS 9 UPDATE It is now a one-liner: ``` UIFont.monospacedDigitSystemFontOfSize(17, weight: UIFontWeightRegular) ``` Also, last time I tried, the solution below did not work for iOS 9. Wasted quite a bit of time debugging before stumbling on this in the header. SOLUTION Turned out to be trivial with Text Kit in iOS 7. Make sure Core Text is imported: ``` #import <CoreText/CoreText.h> ``` Create a setting that converts proportional numbers into monospaced: ``` NSArray *monospacedSetting = @[@{UIFontFeatureTypeIdentifierKey: @(kNumberSpacingType), UIFontFeatureSelectorIdentifierKey: @(kMonospacedNumbersSelector)}]; ``` Create a new font descriptor by appending the current one used by `UILabel`: ``` UIFontDescriptor *newDescriptor = [[timeLabel.font fontDescriptor] fontDescriptorByAddingAttributes:@{UIFontDescriptorFeatureSettingsAttribute: monospacedSetting}]; ``` Update label's font: ``` // Size 0 to use previously set font size timeLabel.font = [UIFont fontWithDescriptor:newDescriptor size:0]; ```

Original source