How to set kerning (spacing between characters) on UINavigationBar title - Swift or Objective-C
Asked Answered
S

4

17

I've got my nav bar mostly customized to my liking, but I'm trying to increase the kerning using NSKernAttributeName. I'm using the appearance proxy to set the nav bar to white text and a custom font, but when I try to add kerning it doesn't take effect.

[[UINavigationBar appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
                                                     [UIColor whiteColor], NSForegroundColorAttributeName,
                                                     [UIFont fontWithName:@"HelveticaNeue-Light" size:20.0], NSFontAttributeName,
                                                     [NSNumber numberWithFloat:2.0], NSKernAttributeName, nil]];

Do I need to do something else to add some of the less common attributes like kerning to the title label?

Schulz answered 1/12, 2013 at 10:0 Comment(0)
D
41

According to the documentation, the titleTextAttributes of UINavigationBar only lets you specify the font, text color, text shadow color, and text shadow offset.

If you want to use other attributes, you can create a UILabel with the NSAttributedString you want, and set it as the titleView for your controller's navigationItem

For example:

UILabel *titleLabel = [UILabel new];
NSDictionary *attributes = @{NSForegroundColorAttributeName: [UIColor whiteColor],
                             NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue-Light" size:20.0],
                             NSKernAttributeName: @2};
titleLabel.attributedText = [[NSAttributedString alloc] initWithString:self.navigationItem.title attributes:attributes];
[titleLabel sizeToFit];
self.navigationItem.titleView = titleLabel;
Dannadannel answered 1/12, 2013 at 10:59 Comment(2)
I overrode setTitle: in a view controller subclass that I share so you don't have to do this everywhere.Eoin
One unfortunate side effect of using a titleView is it seems to mess up some accessibility behaviour. #36991407Doggery
S
8

I've tried many different ways to accomplish this and found that you can only change the font, text color, text shadow color, and text shadow offset of UINavigationBar as @Jesús A. Alvarez above have said.

I've converted the code in Swift and it works:

let titleLabel = UILabel()

let attributes: NSDictionary = [
    NSFontAttributeName:UIFont(name: "HelveticaNeue-Light", size: 20),
    NSForegroundColorAttributeName:UIColor.whiteColor(),
    NSKernAttributeName:CGFloat(2.0)
]

let attributedTitle = NSAttributedString(string: "UINavigationBar Title", attributes: attributes as? [String : AnyObject])

titleLabel.attributedText = attributedTitle
titleLabel.sizeToFit()
self.navigationItem.titleView = titleLabel
Shastashastra answered 17/11, 2015 at 0:16 Comment(0)
L
3

Above answer updated for Swift 4

I created a superclass, where I defined this method, which you can call from each subclass you want:

func setNavigationTitle(_ title: String, kern: CGFloat) {
    let titleLabel = UILabel()

    let attributes = [
        NSAttributedStringKey.font: UIFont.boldSystemFont(ofSize: 18),
        NSAttributedStringKey.foregroundColor: UIColor.white,
        NSAttributedStringKey.kern: kern] as [NSAttributedStringKey : Any]

    let attributedTitle = NSAttributedString(string: title, attributes: attributes)

    titleLabel.attributedText = attributedTitle
    titleLabel.sizeToFit()
    self.navigationItem.titleView = titleLabel
}
Lahdidah answered 20/2, 2018 at 19:15 Comment(1)
I'm curious how you handle very long titles. How do you prevent your titleLabel from covering the right & left navigationItem barButtons? I have been trimming the string after X characters but it's not very precise :(Passepartout
U
0

UIViewController Extension

I converted the above answers into a UIViewController extension to tidy it away.

Swift 3

extension UIViewController {
    func setUpCustomTitleView(kerning: CGFloat) {

        let titleLabel = UILabel()

        guard let customFont = UIFont(name: "Montserrat-SemiBold", size: 18) else { return }

        let attributes = [NSForegroundColorAttributeName: UIColor.gray,
                      NSFontAttributeName: customFont,
                      NSKernAttributeName: kerning] as [String : Any]

        guard let title = title else { return }

        let attributedTitle = NSAttributedString(string: title, attributes: attributes)

        titleLabel.attributedText = attributedTitle
        titleLabel.sizeToFit()
        navigationItem.titleView = titleLabel
    }
}

Call the extension function from the viewDidLoad() of your view controller.

setUpCustomTitleView(kerning: 2.0) 
Unwarrantable answered 3/8, 2017 at 22:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.