48

I want to be able to set the font of my apps navigation bar back button without doing anything too crazy and without losing any other design characteristics of the button (i.e. I want to keep the arrow).

Right now I use this in viewDidAppear: to set the font of the normal bar button items.

for (NSObject *view in self.navigationController.navigationBar.subviews) {
    if ([view isKindOfClass:[UIButton class]]) {
        [((UIButton*)view).titleLabel setFont:[UIFont 
                                 fontWithName:@"Gill Sans" 
                                         size:14.0]];
    }
}

However this makes no change on the back button, regardless of which UIViewController this code is applied to (root, current, etc.).

Alex Cio
  • 6,014
  • 5
  • 44
  • 74
zachjs
  • 1,738
  • 1
  • 11
  • 22
  • Custom stylization of UIBarButton items : http://stackoverflow.com/a/28347428/469614 – Vexy Feb 20 '16 at 14:42

8 Answers8

117

To change the appearance of the text in all UIBarButtonItems appearing in all UINavigationBars, do the following in application:didFinishLaunchingWithOptions:

[[UIBarButtonItem appearanceWhenContainedIn:[UINavigationBar class], nil] setTitleTextAttributes:
    @{UITextAttributeTextColor:[UIColor blackColor],
     UITextAttributeTextShadowOffset:[NSValue valueWithUIOffset:UIOffsetMake(0, 1)],
     UITextAttributeTextShadowColor:[UIColor whiteColor],
     UITextAttributeFont:[UIFont boldSystemFontOfSize:12.0]
    }
     forState:UIControlStateNormal];

UPDATE: iOS7 friendly version

NSShadow *shadow = [[NSShadow alloc] init];
shadow.shadowOffset = CGSizeMake(0.0, 1.0);
shadow.shadowColor = [UIColor whiteColor];

[[UIBarButtonItem appearanceWhenContainedIn:[UINavigationBar class], nil]
 setTitleTextAttributes:
 @{NSForegroundColorAttributeName:[UIColor blackColor],
   NSShadowAttributeName:shadow,
   NSFontAttributeName:[UIFont boldSystemFontOfSize:12.0]
   }
 forState:UIControlStateNormal];

Swift:

NOTE: this changes ALL instances of UIBarButtonItem, not just those contained within a UINavigationBar

UIBarButtonItem.appearance()
               .setTitleTextAttributes([NSFontAttributeName : ExamplesDefaults.fontWithSize(22)], 
                                       forState: UIControlState.Normal)

Swift3:

UIBarButtonItem.appearance()
     .setTitleTextAttributes([NSFontAttributeName: UIFont(name: "FontName-Regular", size: 14.0)!], 
                             for: .normal) 
Nick Weaver
  • 47,228
  • 12
  • 98
  • 108
Mike Pollard
  • 10,195
  • 2
  • 37
  • 46
6

For anyone that did not fully got this to work, here is how i did it, including popped back to the Root ViewController in IOS7:

UIBarButtonItem *backBtn =[[UIBarButtonItem alloc]initWithTitle:@"Back" style:UIBarButtonItemStyleDone target:self action:@selector(popToRoot:)];
backBtn.title = @"Back";
[backBtn setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
                                 [UIFont fontWithName:@"Chalkduster" size:15], NSFontAttributeName,
                                 [UIColor yellowColor], NSForegroundColorAttributeName,
                                 nil]
                       forState:UIControlStateNormal];

self.navigationItem.leftBarButtonItem=backBtn;

popToRoot ViewController:

- (IBAction)popToRoot:(UIBarButtonItem*)sender {
[self.navigationController popToRootViewControllerAnimated:YES];
}

Maybe someone may have use of this.

PeterK
  • 4,243
  • 4
  • 44
  • 74
  • Won't work with locales and throws away the preconfigured accessibility hints needed to get an app into the IAS. You should always use the system provided buttons unless you want to do lots of extra work. –  Jun 01 '15 at 06:38
3

Swift version of the all mentioned above (excerpt from the original answer) :

let customFont = UIFont(name: "customFontName", size: 17.0)!
UIBarButtonItem.appearance().setTitleTextAttributes([NSFontAttributeName: customFont], forState: .normal)

More goodies:
https://stackoverflow.com/a/28347428/469614

Vexy
  • 1,274
  • 1
  • 12
  • 17
2

In Swift3:

let font = UIFont(name: "Verdana", size: 10.0)

// Back button
UIBarButtonItem.appearance().setTitleTextAttributes([NSFontAttributeName: font!], for: UIControlState.normal)  

// Title in the navigation item
let fontAttributes = [NSFontAttributeName: font]
self.navigationController?.navigationBar.titleTextAttributes = fontAttributes

Note: you only have to do this once for the Navigation controller.

Vincent
  • 4,342
  • 1
  • 38
  • 37
2

Swift 3.0+

AppDelegate.swift

UIBarButtonItem.appearance().setTitleTextAttributes([NSAttributedStringKey.font: UIFont(name: "myFont", size: 17.0)!], for: .normal)
smohn
  • 401
  • 1
  • 5
  • 15
1

Use this instead in your AppDelegate or where the NavigationController is initialized, method available in iOS 5 and above

UIBarButtonItem *backbutton =  [[UIBarButtonItem alloc] initWithTitle:@"back" style:UIBarButtonItemStyleBordered target:nil action:nil];  
[backbutton setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
                                                   [UIColor blackColor],UITextAttributeTextColor,[UIFont fontWithName:TEXTFONT size:16.0f],UITextAttributeFont,
                                                   nil] forState:UIControlStateNormal]; 
Ahmed Z.
  • 2,329
  • 23
  • 52
0

If you're using the new UISplitViewControllerDelegate for split views in iOS 8, the above methods won't work because the new displayModeButtonItem works a bit differently.

You need to set the font when you're creating the displayModeButtonItem. Assuming you're following Apple's templates this is probably in prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender where you would do something like this:

// From Apple's Template:
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSManagedObject *object = [[self fetchedResultsController] objectAtIndexPath:indexPath];
DetailViewController *controller = (DetailViewController *)[[segue destinationViewController] topViewController];
[controller setDetailItem:object];
controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
controller.navigationItem.leftItemsSupplementBackButton = YES;
// New Line to set the font:
[controller.navigationItem.leftBarButtonItem setTitleTextAttributes:@{NSFontAttributeName : [UIFont fontWithName:@"SourceSansPro-Regular" size:14]} forState:UIControlStateNormal];
Nick
  • 3,172
  • 3
  • 37
  • 49
  • Actually after more testing, I don't think this works. If anyone has an idea of how to change the font on the `displayModeButtonItem` let me know. – Nick Nov 09 '14 at 07:14
0

If you need to change the title you will use this:

 UINavigationBar.appearance().titleTextAttributes = [
        NSAttributedString.Key.font: UIFont.systemFont(ofSize: 20, weight: UIFont.Weight.heavy)
    ]

But if you need it for your BarButtonItems you can use the below:

UIBarButtonItem.appearance().setTitleTextAttributes([NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 17.0)], for: .normal)

Note: These lines will be added to AppDelegate.Swift File

Menaim
  • 937
  • 7
  • 28