Letter spacing in iOS

David542 picture David542 · Oct 11, 2013 · Viewed 20.2k times · Source

I have the following code:

[[cancelButton titleLabel] setFont:[UIFont fontWithName:@"ProximaNova-Regular" size:15]];

How would I set the letter-spacing as well?

Answer

Tommy picture Tommy · Oct 11, 2013

You can't change the letter spacing in the abstract, which means that you can't change it at all under iOS 5 and below.

As of iOS 6, you can push an attributed string rather than a vanilla one to a UILabel. The process for pushing an attributed string works slightly differently from the process for pushing an ordinary one — the font, text colour and a bunch of other properties are all set on the string rather than on the label. The reason is that attributed strings allow different attributes to be set for different regions of the string. So you can set a string that combines multiple fonts, text colours, etc.

One of the supported Core Text attributes is kCTKernAttributeName, which as of iOS 6 is easier to take advantage of via the UIKit addition NSKernAttributeName. You can use kerning to adjust the horizontal spacing of glyphs.

Under iOS 5 and earlier you used to have to do a lot of mental jumping back and forth between Core Foundation C-style objects and Objective-C UIKit objects. As of 6 that's no longer necessary. But be wary if you search the 'net that things got a lot easier under 6 — if you see lots of __bridge casts and manual CFReleases then you're probably looking at older code.

Anyway, supposing you currently have something like:

UILabel *label = [cancelButton titleLabel];

UIFont *font = <whatever>;
UIColor *textColour = <whatever>;
NSString *string = <whatever>;

label.text = string;
label.font = font;
label.textColor = textColour;

You'd instead do something more like:

NSAttributedString *attributedString = 
    [[NSAttributedString alloc]
          initWithString:string
          attributes:
              @{
                    NSFontAttributeName : font,
                    NSForegroundColorAttributeName : textColour
              }];

label.attributedText = attributedString;

In your case, also to adjust the overall kerning you'd add:

NSAttributedString *attributedString = 
    [[NSAttributedString alloc]
          initWithString:string
          attributes:
              @{
                    NSFontAttributeName : font,
                    NSForegroundColorAttributeName : textColour,
                    NSKernAttributeName : @(-1.3f)
              }];

label.attributedText = attributedString;

Or whatever kerning value you want to apply. See the various constants at the bottom of the NSAttributedString UIKit Additions Reference for the various other attributes you can apply and which version of iOS they first became available on.

Much later addendum: while still being one of the least Swifty people you'll meet, I think this is the equivalent in Swift:

button.titleLabel?.attributedText =
    NSAttributedString(
        string: string,
        attributes:
        [
            NSFontAttributeName: font,
            NSForegroundColorAttributeName: textColour,
            NSKernAttributeName: -1.3
        ])