264
Creating advanced
view controllers
When we started our look at view controllers in chapter 13, we promised that
we’d return to the more advanced view controllers that manage several pages of
content at once. That’s the purpose of this chapter: to introduce you to the final
fundamental building block of the iPhone
OS
that allows you to build complex
multipage applications.
In this chapter we’ll take an in-depth look at two view controllers: the tab bar
controller and the navigation controller. We’ll also take a briefer look at the flipside
controller that appears in one of Xcode’s templates and talk about some modal
controllers that we’ll see in part 4 of this book.
As in our previous chapter on view controllers, we’ll offer some more skeletal
examples since our main purpose is to provide you with the reusable programming
frameworks that will allow you to use these controllers in your own programs. Let’s
kick off our discussion with the tab bar view controller.
This chapter covers
■
Tab-based interfaces
■
Navigation-based interfaces
■
The flipside controller
265The tab bar view controller
15.1 The tab bar view controller
Of the multipage view controllers, the tab bar is the easiest to use because it supports
simple navigation between several views. As with all of the advanced view controllers, it
has a complex underlying structure incorporating several objects that work in tandem.
15.1.1 The anatomy of a tab bar controller
To function, a tab bar view controller requires a hierarchy of at least six objects:
■
One
UITabBarController
■
A minimum of two
UIViewController
s
■
One
UITabBar
■
A minimum of two
UITabBarItem
s
This hierarchy of objects is depicted in figure 15.1.
The tab bar controller and its associated view controllers are the heart of this
setup. Essentially the tab bar controller switches off between different pages, each of
which uses a view controller to manage its events. In Xcode you’d have to create and
hook up these view controllers by hand, while in Interface Builder (which is what we’ll
be using) it’s automated. In either case, you’ll need to fill in the controllers’ views
once your controllers are ready to go.
The tab bar itself is created automatically when you instantiate a tab bar controller.
It displays a set of radio buttons that go at the bottom of the page. Each of those but-
tons is a tab bar item (which Interface Builder also creates automatically). Each tab
bar item then links to an individual view controller. Usually you shouldn’t have to
mess with the tab bar at all; you can do all the modifications you require through
either the tab bar controller or the view controllers.
The connection between the tab bar controller and its tab bar is a simple delega-
tion, as we’ve seen in use in previous chapters. The tab bar has a
delegate
property
that is hooked up to the controller, which must respond to the
UITabBar-
Delegate
protocol.
The tab bar controller can also designate a
delegate
. The controller’s delegate
must follow the
UITabBarControllerDelegate
protocol. This protocol requires
response to two types of high-level events: when the tab bar is rearranged and when a
view controller is selected.
UITabBarController
UIViewControllerUIViewController
UITabBar
UITabBarItemUITabBarItem
Figure 15.1 A collection of six
objects (at minimum) is required
to create a functioning tab bar
controller.
266
C
HAPTER
15
Creating advanced view controllers
15.1.2 Creating a tab bar controller
Each of the advanced view controllers has its own Xcode template that you can use to
immediately instantiate the controller. Since this is our first advanced view controller,
though, we’ll look at how you’d create it by hand before we move over to simpler, tem-
plate-driven object creation.
CREATING YOUR TAB BAR CONTROLLER BY HAND
To create a tab bar controller manually, begin with
the Window-Based Application template. Use it to
create a project imaginatively called “tabex.”
Once you’ve created your project, you should
pop straight over to Interface Builder by clicking on
the MainWindow.xib file.
To create a tab bar controller:
1
Drag the Tab Bar Controller object from the
Library window (where you’ll find it under
Controllers) to the nib display window.
2
Drop the Controller down next to your win-
dow object. When you do that, a tab bar con-
troller Main display window should appear.
3
Dismiss your old Main display; you won’t need
it anymore. Instead you’ll create new objects
as subviews of your tab bar controller.
The results are shown in figure 15.2.
Believe it or not, that’s it. All six objects of note
have been created. The tab bar controller is accessible
from the nib display window. The other five objects
are accessible from the black bar at the bottom of the
Main display window. Click a button once to get its
UIViewController
and a second time to get its
UITabBarItem
. Click in the middle of the strip
(between the buttons) to access the
UITabBar
. By
selecting these items, you can set their attributes, con-
nections, size, and identity.
We took this slight diversion into the “harder”
side of tab bar controller design to show what all the objects look like in Interface
Builder. If you’ve been following on a computer, we suggest clicking around for a
while to see how everything works. Once you’ve seen all of the fundamental objects
that are created as part of an advanced view controller, we’ve played the Window-
Based Application template’s last trick. In the future we’re just going to jump straight
to the appropriate template for each sort of view controller—starting with the tab bar
controller template.
Figure 15.2 Just dragging a tab bar
controller to the nib display window
creates the whole tab bar interface.
267The tab bar view controller
CREATING YOUR TAB BAR THROUGH A TEMPLATE
It’s even easier to create a tab bar controller using the existing tab bar template. Just
select Tab Bar Application when you create a new project. This template will set you
up with a tab bar controller much like the one you just created by hand, except it does
three additional things:
■
The template defines the tab bar controller as an
IBOutlet
, giving the app del-
egate access to the object
IBOutlet
UITabBarController
*tabBarController;
■
The template creates the view controller for the first window as part of a special
FirstViewController
class. You’ll probably want to have an individual view
controller class for each tab to take care of events on a per-page basis, but that is
easy enough to change by adding class files and adjusting the Identity tab for
the view controllers. For now, leave things as they are so that we can examine
how to work with the default template setup.
■
The template associates a second .xib file with the second view. It does this in a
way we’ve seen before, by defining a nib Name for the view controller inside
Interface Builder.
For the rest of this section, we’re going to assume that you’re working with this pre-
built tab bar controller template as your “tabex” project.
With a working tab bar controller in hand, we can now start programming multi-
ple pages of screens.
15.1.3 Building a tab bar interface
At this point you’ve got a tab bar controller that contains two tabs, each of which has
relatively empty content. You’ve also got tabs on your tab bar without pictures and
without meaningful names. To build your tab bar interface, you’ll want to adjust all of
these things.
ADDING MORE TABS
Inside Interface Builder you add tabs to the tab bar by going to the Attributes tab of
the tab bar controller and clicking the plus sign (+) in its view controller area. A tab
Tab bars and toolbars
The
UIKit
supports two very similar interfaces, the
UITabBar
and the
UIToolBar
.
They each include a strip of icons that goes along the bottom of the screen. Their
main difference is in functionality.
The
UITabBar
is intended as a modal interface that changes the selections when
they’re tapped (usually with a permanent highlight). The purpose of the
UIToolBar
is
to provide a menu of possible actions that don’t change the appearance of the se-
lection when tapped (except with a temporary highlight).
Despite their similar appearance, the two items share no inheritance other than a
common ancestor in
UIView
. Consider it convergent evolution.
We’ll present a fully functional example of a
UIToolBar
in chapter 18, section 18.4.
268
C
HAPTER
15
Creating advanced view controllers
bar item and related view controller will be added to the right-hand side of your bar.
Go ahead and create a third tab by clicking the +.
To allow for easy access to this new controller’s view, you’ll probably want to create
a new .xib file and connect the view controller to that .xib file. Both of these proce-
dures were described at the end of chapter 12.
CONNECTING VIEWS
Once you have the right number of tabs, you can then connect views to each of the tab
bar’s view controllers. This can be done in three major ways:
■
You can input views through .xib files, as noted earlier.
■
If a view controller has its own class file, you can add views through the
load-
View
or
viewDidLoad
method for that class.
■
If a view controller doesn’t have its own class file, you can load views elsewhere,
such as in the app delegate’s
applicationDidFinishLaunching:
.
We’ve already offered several examples for the first two ways to load views (including
plenty of Interface Builder examples in chapter 12 and
viewDidLoad:
examples in
chapter 13), so we’re not going to repeat those methods here. Instead, since the latter
two view controllers don’t have their own class files, you’ll see how you can create their
views using
applicationDidFinishLaunching:
. Honestly, it’d probably be simpler to
create their views in Interface Builder, but this example will demonstrate how you can
use the tab bar controller.
Although you don’t have outlets for the controllers themselves, you can link to
them straight from the tab bar controller object, which you do have access to, thanks
to that
IBOutlet
that we’re already seen. This relates to a concept that we discussed
when talking about basic view controllers in chapter 13; since view controllers have to
do MVC management, they should give you easy access to related objects. Within the
tab bar controller is a
viewControllers
property, which is an
NSArray
list of the view
controllers that a tab bar controller contains.
Listing 15.1 shows how to access this information and programmatically build a
couple of views for the second and third controller within tabexAppDelegate.m. This
is the skeleton of a simple program that would let you edit a text view in the first win-
dow, keep a count of what you’ve written in the second, and search in the third.
- (void)applicationDidFinishLaunching:(UIApplication *)application {
UIViewController *secondController =
[tabBarController.viewControllers objectAtIndex:1];
UIViewController *thirdController =
[tabBarController.viewControllers objectAtIndex:2];
UITextView *secondView = [[UITextView alloc]
initWithFrame:[[UIScreen mainScreen] bounds]];
secondView.text = @"A word count would appear here.";
secondView.editable = NO;
Listing 15.1 A tab bar controller setup
Retrieves
view
controllers
B
269The tab bar view controller
secondController.view = secondView;
UITextView *thirdView = [[UITextView alloc]
initWithFrame:[[UIScreen mainScreen] bounds]];
thirdView.text = @"A search function would go here.";
thirdView.editable = NO;
thirdController.view = thirdView;
[window addSubview:tabBarController.view];
[secondView release];
[thirdView release];
}
To access the view controllers, you just pull elements out of an array using the appro-
priate
NSArray
calls
B
. You then associate views with each view controller, as you’ve
done in the past
C
. Finally you link the tab bar controller to the window, using a call
that was already sitting in your file when you loaded it
D
.
You now have three modal pages (including that first controller’s page, which we
assume was taken care of in its class files, provided by default by the template). Each
does what you want, and navigation between them is easy. But you can still do some
work to make your tab bar look better.
MODIFYING THE BUTTONS
Although we have views associated with each button, the
buttons just say First, Second, and Third, rather than
providing any useful clue as to a button’s purpose. You
can change three things on each button to improve their
usability: the icon, the title, and the badge. Figure 15.3
shows the goal, which is to fill out some or all of this
information for each of our tab buttons.
The icon is the image that appears on the tab bar
item. This image can only be set when you create a tab
bar item. If you were creating the tab bar programmat-
ically, you’d use the
initWithTitle:image:tag:
meth-
od when creating the tab bar item. More likely, you’ll just
go into Interface Builder and load a small
PNG
graphic
that you want to use.
This process is similar to incorporating the image
into your project in chapter 12. You should create a
transparent
PNG
that’s approximately 30 x 30. If your
image is too big, the
SDK
will resize it, but it’s better to
start off at the right size. After you drag the image into
your project, you’ll be able to load it up in Interface
Builder. We used a Wingdings font to create the simple
images that appeared in figure 15.3.
Sets views
C
Displays tab bar
controller
D
Figure 15.3 You can customize
tab bars to make navigation clear
and simple.
270
C
HAPTER
15
Creating advanced view controllers
The title is the word that appears on the tab bar. You’ll probably set that in Inter-
face Builder too, which just involves going to the tab in question and changing the
text there.
If you want to later change the title during runtime, it is accessible in Xcode. The
catch is that these titles aren’t found in the tab bar controller. Instead, they follow the
overarching idea of
MVC
: since a view controller is responsible for an individual view,
it’s the controller that actually sets the title of the page. This is done with the view con-
troller’s
title
property, which we’ve mentioned before and which we’ll meet again:
secondController.title = @"Word Count";
The badge is the little red circle that appears above the title and over the icon on the tab
bar. As always, you could change this in Interface Builder, but Xcode is where you’ll gen-
erally want to do this work. That’s because the information in a badge is meant to be
dynamic, changing as the view changes and alerting a user to new content during run-
time. It’s badges, for example, that tell you when you have new mail or new voicemail.
Getting to the badge property is a two-step process. You’ll start with your view con-
troller. From there you access
tabBarItem
, which is a property of the controller that
links you to its connected tab bar item, and then
badgeValue
, which is a property of
the tab bar item. Fortunately, this can all be done as one nested line:
secondController.tabBarItem.badgeValue = @"16";
The
16
, as it happens, is the initial character count of the main text view. If you were
building a live program, you could change this count over the course of your program’s
runtime.
Table 15.1 summarizes the three main elements of the tab bar and how to custom-
ize them.
There’s one more way to change both the icon and the title of a tab bar item simulta-
neously: by creating a tab bar item with the
initWithTabBarSystemItem:tag:
method. This creates a tab bar using one of the constants defined under
UITabBar-
SystemItem
, each of which relates to a standard iPhone function and correlates a
name and a picture with that function.
You’ll probably be doing this in Interface Builder, where you select a specific
“Identifier” instead of entering a title and a picture. Since your third tab allows
searches, you can initialize it as a
UITabBarSystemItemSearch
button, which gives it
the title of “Search” and the picture of a magnifying glass, as shown in figure 15.3.
Once you’ve got the tab bar all set up, you’re ready to start using the controller.
Table 15.1 From your view controllers, it’s easy to customize the associated tab bar items.
Property Summary Interface builder Xcode
badge
Tab bar info Yes
viewcontroller.tabBarItem.badgeValue
icon
Tab bar picture Yes
only at
init
title
Tab bar words Yes
viewcontroller.title