« Wantrepreneer   Action Trees »

12 Feb 2014

iOS Shared BarButtonItems 

TL;DR Version

You can use the following UINavigationControllerDelegate method to set up the NavigationItems for all child ViewControllers:

- (void)navigationController:(UINavigationController *)navigationController
willShowViewController:(UIViewController *)viewController animated:(BOOL)animated

Not-Long-Enough; Tell Me More Version

Here’s one difficulty I ran into this week that had a less-than-obvious solution…

The Problem

In my iOS app, I wanted every UINavigationController’s child ViewController to have the same rightBarButtonItem.

Specifically, I wanted every child to show the “+” (Add) button and for the “+” button to behave the same, regardless of which screen it was touched in.

Unfortunately, storyboards don’t make this very easy to do in a DRY manner.

The Solution

The solution basically has two parts:

  1. “Hack” the storyboard to add the shared BarButtonItem directly to the NavigationController.

Part 1: Hacking the storyboard

In order to display the common BarButtonItem, you will need the NavigationController to have a NavigationItem. However, by default a NavigationController object will contain a NavigationBar only and won’t allow adding any more objects.

To get around this, I discovered the following trick:

  1. Create a NavigationController object by dragging from the Object library onto an empty section of the canvas.
  2. Select the newly-created RootViewController.
  3. Use the Editor menu to select Embed In->Navigation Controller.

  4. The new NavigationController object will have a NavigationItem.

  5. Integrate the new NavigationController into your “actual” storyboard and clean up the unnecessary elements from the last few steps.

Now, you can drag a BarButtonItem onto the NavigationController’s NavigationItem.

This will help with visualizing how the navigationBar will look, but more importantly, it will also help with achieving DRYness, as shown in part two below.

Part 2: Subclassing UINavigationController

Now, you will need to link the BarButtonItem to an IBOutlet and an IBAction:

  1. Create a subclass of UINavigationController.
    • In the storyboard, set the Custom Class of the NavigationController to be your new class.
    • Show the Assistant Editor and control-drag from the BarButtonItem into your new class’s .m file to create an outlet and an action for the BarButtonItem.

The final step is to programmatically add the BarButtonItem to all child ViewControllers. First, tell your new class to conform to the UINavigationControllerDelegate protocol. Then, add this code to your new class, replacing “addButton” with the name of your IBOutlet property:

- (void)viewDidLoad
    [super viewDidLoad];
    self.delegate = self;

- (void)navigationController:(UINavigationController *)navigationController
    willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
    if (!viewController.navigationItem.rightBarButtonItem) {
        viewController.navigationItem.rightBarButtonItem = self.addButton;

IMPORTANT: Note the condition inside the “if” statement. This will allow you to override the rightBarButtonItem on a per-screen basis later, if you want. But for now, make sure you remove any rightBarButtonItems from child ViewControllers. Therefore, in your storyboard, your navigation path should look like this (only one “+” button):

That’s it! Now you can implement whatever you’d like in your IBAction method and the functionality will be the same on every screen.


comments powered by Disqus