1.15. Adding Buttons to Navigation Bars Using UIBarButtonItem

Problem

You want to add buttons to a navigation bar.

Solution

Use the UIBarButtonItem class.

Discussion

A navigation bar can contain different items. Buttons are often displayed on the left and the right sides. These buttons are of class UIBarButtonItem and can take many different shapes and forms. Let’s have a look at an example in Figure 1-36.

Different buttons displayed on a navigation bar

Figure 1-36. Different buttons displayed on a navigation bar

Navigation bars are of class UINavigationBar and can be created at any time and added to any view. Just look at all the different buttons with different shapes that have been added to the navigation bar in Figure 1-36. The ones on the top right have up and down arrows, and the one on the top left has an arrow pointing to the left. We will have a look at creating some of these buttons in this recipe.

Note

For this recipe, you must follow the instructions in Creating and Running Our First iOS App to create an empty application. Then follow the instructions in Recipe 1.12 to add a navigation controller to your app delegate.

In order to create a navigation button, we must do the following:

  1. Create an instance of UIBarButtonItem.

  2. Add that button to the navigation bar of a view controller using the view controller’s navigationItem property. The navigationItem property allows us to interact with the navigation bar. This property has two others on itself: rightBarButtonItem and leftBarButtonItem. Both these properties are of type UIBarButtonItem.

Let’s then have a look at an example where we add a button to the right side of our navigation bar. In this button, we will display the text “Add”:

- (void) performAdd:(id)paramSender{
    NSLog(@"Action method got called.");
}

- (void)viewDidLoad{
    [super viewDidLoad];

    self.title = @"First Controller";

    self.navigationItem.rightBarButtonItem =
    [[UIBarButtonItem alloc] initWithTitle:@"Add"
                                     style:UIBarButtonItemStylePlain
                                    target:self
                                    action:@selector(performAdd:)];
}

When we run our app now, we will see something similar to Figure 1-37.

A navigation button added to a navigation bar

Figure 1-37. A navigation button added to a navigation bar

That was easy. But if you are an iOS user, you probably have noticed that the system apps that come preconfigured on iOS have a different Add button. Figure 1-38 shows an example in the Alarm section of the Clock app on the iPhone (notice the + button on the top right of the navigation bar).

The proper way of creating an Add button

Figure 1-38. The proper way of creating an Add button

It turns out that the iOS SDK allows us to create system buttons on the navigation bar. We do that by using the initWithBarButtonSystemItem:target:action: initializer of the UIBarButtonItem class:

- (void) performAdd:(id)paramSender{
    NSLog(@"Action method got called.");
}

- (void)viewDidLoad{
    [super viewDidLoad];

    self.title = @"First Controller";

    self.navigationItem.rightBarButtonItem =
    [[UIBarButtonItem alloc]
     initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
     target:self
     action:@selector(performAdd:)];
}

And the results are exactly what we were looking for (Figure 1-39).

A system Add button

Figure 1-39. A system Add button

The first parameter of the initWithBarButtonSystemItem:target:action: initializer method of the navigation button can have any of the values listed in the UIBarButtonSystemItem enumeration:

typedef NS_ENUM(NSInteger, UIBarButtonSystemItem) {
    UIBarButtonSystemItemDone,
    UIBarButtonSystemItemCancel,
    UIBarButtonSystemItemEdit,
    UIBarButtonSystemItemSave,
    UIBarButtonSystemItemAdd,
    UIBarButtonSystemItemFlexibleSpace,
    UIBarButtonSystemItemFixedSpace,
    UIBarButtonSystemItemCompose,
    UIBarButtonSystemItemReply,
    UIBarButtonSystemItemAction,
    UIBarButtonSystemItemOrganize,
    UIBarButtonSystemItemBookmarks,
    UIBarButtonSystemItemSearch,
    UIBarButtonSystemItemRefresh,
    UIBarButtonSystemItemStop,
    UIBarButtonSystemItemCamera,
    UIBarButtonSystemItemTrash,
    UIBarButtonSystemItemPlay,
    UIBarButtonSystemItemPause,
    UIBarButtonSystemItemRewind,
    UIBarButtonSystemItemFastForward,
#if __IPHONE_3_0 <= __IPHONE_OS_VERSION_MAX_ALLOWED
    UIBarButtonSystemItemUndo,
    UIBarButtonSystemItemRedo,
#endif
#if __IPHONE_4_0 <= __IPHONE_OS_VERSION_MAX_ALLOWED
    UIBarButtonSystemItemPageCurl,
#endif
};

One of the really great initializers of the UIBarButtonItem class is the initWithCustomView: method. As its parameter, this method accepts any view. This means we can even add a UISwitch (see Recipe 1.2) as a button on the navigation bar. This won’t look very good, but let’s give it a try:

- (void) switchIsChanged:(UISwitch *)paramSender{
    if ([paramSender isOn]){
        NSLog(@"Switch is on.");
    } else {
        NSLog(@"Switch is off.");
    }
}

- (void)viewDidLoad{
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    self.title = @"First Controller";

    UISwitch *simpleSwitch = [[UISwitch alloc] init];
    simpleSwitch.on = YES;
    [simpleSwitch addTarget:self
                     action:@selector(switchIsChanged:)
           forControlEvents:UIControlEventValueChanged];

    self.navigationItem.rightBarButtonItem =
    [[UIBarButtonItem alloc] initWithCustomView:simpleSwitch];
}

And Figure 1-40 shows the results.

A switch added to a navigation bar

Figure 1-40. A switch added to a navigation bar

You can create pretty amazing navigation bar buttons. Just take a look at what Apple has done with the up and down arrows on the top-right corner of Figure 1-36. Let’s do the same thing, shall we? Well, it looks like the button actually contains a segmented control (see Recipe 1.8). So we should create a segmented control with two segments, add it to a navigation button, and finally place the navigation button on the navigation bar. Let’s get started:

- (void) segmentedControlTapped:(UISegmentedControl *)paramSender{

    switch (paramSender.selectedSegmentIndex){
        case 0:{
            NSLog(@"Up");
            break;
        }
        case 1:{
            NSLog(@"Down");
            break;
        }
    }

}

- (void)viewDidLoad{
    [super viewDidLoad];

    self.title = @"First Controller";

    NSArray *items = @[
                       @"Up",
                       @"Down"
                       ];

    UISegmentedControl *segmentedControl = [[UISegmentedControl alloc]
                                            initWithItems:items];

    segmentedControl.momentary = YES;

    [segmentedControl addTarget:self
                         action:@selector(segmentedControlTapped:)
               forControlEvents:UIControlEventValueChanged];

    self.navigationItem.rightBarButtonItem =
    [[UIBarButtonItem alloc] initWithCustomView:segmentedControl];

}

And Figure 1-41 shows what the output looks like.

A segmented control inside a navigation button

Figure 1-41. A segmented control inside a navigation button

The navigationItem of every view controller also has two very interesting methods:

setRightBarButtonItem:animated:

Sets the navigation bar’s right button.

setLeftBarButtonItem:animated:

Sets the navigation bar’s left button.

Both methods allow you to specify whether you want the placement to be animated. Pass the value of YES to the animated parameter if you want the placement to be animated. Here is an example:

UIBarButtonItem *rightBarButton =
[[UIBarButtonItem alloc] initWithCustomView:segmentedControl];

[self.navigationItem setRightBarButtonItem:rightBarButton
                                  animated:YES];

Get iOS 7 Programming Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.