I am rendering numbers in iOS (targeting 7 and up) by storing them in an NSAttributedString and rendering with "drawAtPoint:". I am using Helvetica Neue.
I have noticed that digits of numbers drawn like this are not proportional – the glyphs all have the same width. Even a skinny "1" takes up the same space as a "0".
A test confirms this:
for(NSInteger i=0; i<10; ++i)
{
NSString *iString = [NSString stringWithFormat: @"%d", i];
const CGSize iSize = [iString sizeWithAttributes: [self attributes]];
NSLog(@"Size of %d is %f", i, iSize.width);
}
With, elsewhere:
-(NSDictionary *) attributes
{
static NSDictionary * attributes;
if(!attributes)
{
attributes = @{
NSFontAttributeName: [UIFont systemFontOfSize:11],
NSForegroundColorAttributeName: [UIColor whiteColor]
};
}
return attributes;
}
This resulting glyphs all have the same width of 6.358 points.
Is there some rendering option I can turn on that to enable proportional digit glyphs? Is there another font (ideally similar to Helvetica Neue) that supports proportional digit glyphs (ideally, built in)? Anything else?
Thank you.
iOS 7 lets you specify fonts using UIFontDescriptor
instances. A UIFont
instance is then obtained from a descriptor.
Given a UIFontDescriptor
it is also possible to obtain a customisation of it that changes some characteristics by using the method [fontDescriptor fontDescriptorByAddingAttributes: attibutes]
where attributes
is an NSDictionary
of font attributes.
Apple documents the attributes in the UIFontDescriptor
reference.
From the reference, one particular font descriptor attribute UIFontDescriptorFeatureSettingsAttribute
lets you provide "An array of dictionaries representing non-default font feature settings. Each dictionary contains UIFontFeatureTypeIdentifierKey
and UIFontFeatureSelectorIdentifierKey
."
Documentation of the UIFontFeatureTypeIdentifierKey
s and UIFontFeatureSelectorIdentifierKey
s is in Apple's Font Registry documentation. The specific case of proportional digits is covered in this pdf of slides of an Apple presentation, so I just lifted that.
This code that will take an existing UIFont
instance and give you back a new instance with proportional digits:
// You'll need this somewhere at the top of your file to pull
// in the required constants.
#import <CoreText/CoreText.h>
…
UIFont *const existingFont = [UIFont preferredFontForTextStyle: UIFontTextStyleBody];
UIFontDescriptor *const existingDescriptor = [existingFont fontDescriptor];
NSDictionary *const fontAttributes = @{
// Here comes that array of dictionaries each containing UIFontFeatureTypeIdentifierKey
// and UIFontFeatureSelectorIdentifierKey that the reference mentions.
UIFontDescriptorFeatureSettingsAttribute: @[
@{
UIFontFeatureTypeIdentifierKey: @(kNumberSpacingType),
UIFontFeatureSelectorIdentifierKey: @(kProportionalNumbersSelector)
}]
};
UIFontDescriptor *const proportionalDescriptor = [existingDescriptor fontDescriptorByAddingAttributes: fontAttributes];
UIFont *const proportionalFont = [UIFont fontWithDescriptor: proportionalDescriptor size: [existingFont pointSize]];
You could add this as a category on UIFont
if you wished, etc.
Edit note: thanks to Chris Schwerdt for the improvements.