1.16. Presenting Multiple View Controllers with UITabBarController

Problem

You would like to give your users the option to switch from one section of your app to another, with ease.

Solution

Use the UITabBarController class.

Discussion

If you use your iPhone as an alarm clock, you have certainly seen a tab bar. Have a look at Figure 1-38. The bottom icons labeled World Clock, Alarm, Stopwatch, and Timer are parts of a tab bar. The whole black bar at the bottom of the screen is a tab bar, and the aforementioned icons are tab bar items.

A tab bar is a container controller. In other words, we create instances of UITabBarController and add them to the window of our application. For each tab bar item, we add a navigation controller or a view controller to the tab bar, and those items will appear as tab bar items. A tab bar controller contains a tab bar of type UITabBar. We don’t create this object manually. We create the tab bar controller, and that will create the tab bar object for us. To make things simple, remember that we instantiate a tab bar controller and set the view controllers of that tab bar to instances of either UIViewController or UINavigationController if we intend to have navigation controllers for each of the tab bar items (aka, the view controllers set for the tab bar controller). Navigation controllers are of type UINavigationController that are subclasses of UIViewController. Therefore, a navigation controller is a view controller, but view controllers of type UIViewController are not navigation controllers.

So let’s assume we have two view controllers with class names FirstViewController and SecondViewController.

- (BOOL)            application:(UIApplication *)application
  didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

    self.window = [[UIWindow alloc] initWithFrame:
                   [[UIScreen mainScreen] bounds]];

    [self.window makeKeyAndVisible];

    FirstViewController *firstViewController = [[FirstViewController alloc]
                                                initWithNibName:nil
                                                bundle:NULL];
    SecondViewController *secondViewController = [[SecondViewController alloc]
                                                  initWithNibName:nil
                                                  bundle:NULL];

    UITabBarController *tabBarController = [[UITabBarController alloc] init];
    [tabBarController setViewControllers:@[firstViewController,
                                           secondViewController
                                           ]];

    self.window.rootViewController = tabBarController;

    return YES;

}

A tab bar, when displayed on the screen, will display tab bar items just like those we saw in Figure 1-38. The name of each of these tab bar items comes from the title of the view controller that is representing that tab bar item, so let’s go ahead and set the title for both of our view controllers.

Warning

When a tab bar loads up, it loads only the view of the first view controller in its items. All other view controllers will be initialized, but their views won’t be loaded. This means that any code that you have written in the viewDidLoad of the second view controller will not get executed until after the user taps on the second tab bar item for the first time. So if you assign a title to the second view controller in its viewDidLoad and run your app, you will find that the title in the tab bar item is still empty.

For the first view controller, we choose the title First:

#import "FirstViewController.h"

@implementation FirstViewController

- (id)initWithNibName:(NSString *)nibNameOrNil
               bundle:(NSBundle *)nibBundleOrNil{

    self = [super initWithNibName:nibNameOrNil
                           bundle:nibBundleOrNil];
    if (self != nil) {
        self.title = @"First";
    }
    return self;

}

- (void)viewDidLoad{
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
}

And for the second view controller, we pick the title Second:

#import "SecondViewController.h"

@implementation SecondViewController

- (id)initWithNibName:(NSString *)nibNameOrNil
               bundle:(NSBundle *)nibBundleOrNil{

    self = [super initWithNibName:nibNameOrNil
                           bundle:nibBundleOrNil];
    if (self != nil) {
        self.title = @"Second";
    }
    return self;

}

- (void)viewDidLoad{
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
}

Now let’s run our app and see what happens (Figure 1-42).

A very simple tab bar populated with two view controllers

Figure 1-42. A very simple tab bar populated with two view controllers

You can see that our view controllers do not have a navigation bar. What should we do? It’s easy. Remember that a UINavigationController is actually a subclass of UIViewController. So we can add instances of navigation controllers to a tab bar, and inside each navigation controller, we can load a view controller. What are we waiting for, then?

- (BOOL)            application:(UIApplication *)application
  didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

    // Override point for customization after application launch.
    self.window = [[UIWindow alloc] initWithFrame:
                   [[UIScreen mainScreen] bounds]];

    [self.window makeKeyAndVisible];

    FirstViewController *firstViewController = [[FirstViewController alloc]
                                                initWithNibName:nil
                                                bundle:NULL];

    UINavigationController *firstNavigationController =
        [[UINavigationController alloc]
         initWithRootViewController:firstViewController];

    SecondViewController *secondViewController = [[SecondViewController alloc]
                                                  initWithNibName:nil
                                                  bundle:NULL];

    UINavigationController *secondNavigationController =
        [[UINavigationController alloc]
         initWithRootViewController:secondViewController];

    UITabBarController *tabBarController = [[UITabBarController alloc] init];

    [tabBarController setViewControllers:
        @[firstNavigationController, secondNavigationController]];

    self.window.rootViewController = tabBarController;

    return YES;

}

And the results? Exactly what we wanted (Figure 1-43).

As we can see in Figure 1-38, each tab bar item can have text and an image. We’ve learned that, using the title property of a view controller, we can specify this text, but what about the image? It turns out that every view controller has a property called tabItem. This property is the tab item for the current view controller, and you can use this property to set the image of the tab bar item through the image property of the tab item. I’ve already designed two images, a rectangle and a circle. I’m going to display them as the tab bar item image for each of my view controllers. Here is code for the first view controller:

- (id)initWithNibName:(NSString *)nibNameOrNil
               bundle:(NSBundle *)nibBundleOrNil{

    self = [super initWithNibName:nibNameOrNil
                           bundle:nibBundleOrNil];
    if (self != nil) {
        self.title = @"First";
        self.tabBarItem.image = [UIImage imageNamed:@"FirstTab"];
    }
    return self;

}

- (void)viewDidLoad{
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
}

And here it is for the second view controller:

- (id)initWithNibName:(NSString *)nibNameOrNil
               bundle:(NSBundle *)nibBundleOrNil{

    self = [super initWithNibName:nibNameOrNil
                           bundle:nibBundleOrNil];
    if (self != nil) {
        self.title = @"Second";
        self.tabBarItem.image = [UIImage imageNamed:@"SecondTab"];
    }
    return self;

}

- (void)viewDidLoad{
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
}

Running the app in the simulator, we will see that the images are displayed properly (Figure 1-44).

A tab bar displaying view controllers inside navigation controllers

Figure 1-43. A tab bar displaying view controllers inside navigation controllers

Tab bar items with images

Figure 1-44. Tab bar items with images

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.