Chapter 15. Creating advanced view controllers

This chapter covers

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.

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 UIViewControllers
  • One UITabBar
  • A minimum of two UITabBarItems

This hierarchy of objects is depicted in figure 15.1.

Figure 15.1. A collection of six objects (at minimum) is required to create a functioning tab bar controller.

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 buttons 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 delegation, 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.

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, template-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 window object. When you do that, a tab bar controller 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.

Figure 15.2. Just dragging a tab bar controller to the nib display window creates the whole tab bar interface.

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, connections, 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.

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 delegate 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 multiple pages of screens.


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 selection 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.


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 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 procedures 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 window, keep a count of what you’ve written in the second, and search in the third.

Listing 15.1. A tab bar controller setup

To access the view controllers, you just pull elements out of an array using the appropriate NSArray calls . You then associate views with each view controller, as you’ve done in the past . Finally you link the tab bar controller to the window, using a call that was already sitting in your file when you loaded it .

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.

Figure 15.3. You can customize tab bars to make navigation clear and simple.

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 programmatically, you’d use the initWithTitle:image:tag: method 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 × 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.

The title is the word that appears on the tab bar. You’ll probably set that in Interface 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 controller’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 generally 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 runtime. 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 controller. 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 customize them.

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

There’s one more way to change both the icon and the title of a tab bar item simultaneously: by creating a tab bar item with the initWithTabBarSystemItem:tag: method. This creates a tab bar using one of the constants defined under UITabBarSystemItem, 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.

15.1.4. Using your tab bar controller

The main function of a tab bar is to allow navigation between multiple pages in your application. This is an implicit function of the object and you don’t need to do anything more to enable it. The rest of the tab bar controller’s functionality goes beyond our basic overview of the topic, but we’ll mention it briefly. There are two main elements you want to consider: customization and delegation.

Tab Bar Customization

One of the neat things about a tab bar is that users can customize them to contain exactly the tab bar items that interest them. You can allow this by setting the customizableViewControllers property to include a list of view controllers that can be changed by the user:

tabBarController.customizableViewControllers =
tabBarController.viewControllers;

The UITabBar reference contains all the information you’ll need on managing customization itself.

Tab Bar Controller Delegation

As we noted, you can set a delegate for your tab bar controller to hand off the scant amount of event management that it requires. The delegate object must follow the UITabBarControllerDelegate protocol, which is a fancy way of saying that it’ll respond to two specific events: one when a view controller is selected and another when the tab bar controller is customized. There’s a protocol reference that covers the specifics of this.

Two methods are associated with these protocols. tabBarController:didEndCustomizingViewControllers:changed: reports the end of tab bar customization and tabBarController:didSelectViewController: reports when the user switches between controllers. The latter is probably more generally useful. For example, you might use it in your word count example to recalculate the word count totals whenever a user jumps to the word count page.

But now that you’ve got a basic example of how to navigate with a tab bar, you’re ready for the next advanced controller: the navigation controller.

15.2. The navigation controller

The navigation controller is probably the most-seen user-interface item on the iPhone. Whenever you have a hierarchical set of pages where you can move up or down through the hierarchy, that’s the navigation controller at work. It appears in the Text, Calendar, Photos, and Notes iPhone utilities, just to name a few.

Working with the navigation controller is a bit harder than working with the tab bar controller, because you have to manage your hierarchy of views live as the user interacts with your program, but the SDK still keeps it simple.

As with our previous view controllers, we’ll look at an overview of the class, and then examine how to create, build, and use a navigation controller. Let’s get started with an overview of its hierarchy.

15.2.1. The anatomy of a navigation controller

As with the tab bar controller, the navigation controller involves a whole hierarchy of items. The UINavigationController sits atop a stack of UIViewControllers that can be pushed or popped as a user moves up and down through it.

Each of these controllers also has an associated UINavigationItem, which will sit in the UINavigationBar when it’s active. Each UINavigationItem may also contain one or more UIBarButtonItems, which allow for additional action items to sit on the navigation bar.

To tie things back together, the UINavigationBar is also linked to the UINavigationController so that navigation items and view controllers stay in sync over the course of a program’s runtime. Whenever a UIViewController loads into the UINavigationController, its UINavigationItem also loads into the UINavigationBar.

A minimalistic navigation controller has just four objects in it: the UINavigation-Controller, the UINavigationBar, a stack containing a single UIViewController, and a UINavigationItem (which is placed into the UINavigationBar). Presumably more view controllers and associated navigation items will be added to the stack as the program runs.

This is all illustrated in figure 15.4.

Figure 15.4. The navigation controller will contain at least four objects, and may be built into a complex web of interconnections.

You’ll note how similar this diagram of navigation controller parts looks to figure 15.1, our diagram of tab bar controller parts. This is not an accident in our drawing, nor do we expect that it was an accident in Apple’s design. The navigation controller works quite a bit like the tab bar controller, and thus we’ll see familiar elements, such as the title of the view controller creating the title within the navigator itself.

The biggest difference is that where the tab bar controller presented a modal paradigm, entirely organized by the controller itself, the navigation controller instead creates a hierarchical paradigm. The navigation controller doesn’t have any particular sense of the organization of the entire structure. Instead, a linked list is created, with each navigation item only knowing about the pages on either side of it.

A Note on Table Views

The standard iPhone paradigm is to do hierarchical navigation through table views, each of which contains lists of many different subpages that you can go to. As a result, despite the fact that any UIViewController could sit beneath a UINavigation-Controller, it’ll usually be a UITableViewController.

This is exactly the setup we’ll see in the navigation-based template.

15.2.2. Creating a navigation controller

To create a navigation controller, create a new project (which we’re calling “navex”) using the Navigation-Based Application template. You can page through the .xib file and the Xcode listing to see what you’ve been given. Let’s start with the .xib files, whose content you can see in figure 15.5.

Figure 15.5. The navigation controller template contains two .xib files, one for the main view (left) and one for what appears inside the controller (right).

Mainwindow.xib contains a UINavigationController in the nib window with a UINavigationBar hidden under it. The main display window contains a UINavigation-Item and a RootViewController. The latter is a subclass of UITableViewController created through Xcode, just as when you designed your own table controller in chapter 13. Note that this sets up the standard iPhone paradigm of navigation controllers being built atop table controllers. The table view controller’s contents are instantiated through a second .xib file, RootViewController.xib, as shown in the table view controller’s attributes window.

RootViewController.xib is a boring .xib file because it just contains a table view. Consider it a good example of how pairing .xib files with view controllers can keep your program well organized.

Finally, if you look at your Xcode files created by the template, you can see that the navigation controller gets linked to your window in the app delegate file. Among the other default files are the RootViewController class files you’d expect to see. Since you’re working with a table view controller, you know the RootViewController class files will be important when you input the table view’s data.

15.2.3. Building a navigation controller

At this point we’ll do three things to complete the navigation controller: add a title, add navigation links, and (optionally) add action buttons.

Adding a Title

Just like the tab bar controller, the navigation controller takes its title from the title of the individual page’s view controller. All you have to do is define title in your table view controller file:

   self.title = @"Color List";

This turns out to be a critical bit of data, because it’s also what the navigation controller will use as a back button when you’re deeper in the hierarchy.

Adding the Links

You could theoretically use whatever method you want to link to additional pages via a navigational controller. The default mechanism is to use a table list, and that’s the method we’ll use in this example.

Design your table view controller as we discussed in chapter 13, but this time you should give each table cell an accessory view of type UITableViewCellAccessoryDisclosureIndicator. That’s the standard chevron used to indicate hierarchical navigation.

Listing 15.2 includes all of the major elements required to define this navigation table inside RootViewController.m.

Listing 15.2. A table for a navigator
 - (id)initWithCoder:(NSCoder *)decoder {

self = [super initWithCoder:decoder];
if (self) {
self.title = @"Color List";
colorList = [NSArray arrayWithObjects:
[NSDictionary dictionaryWithObjectsAndKeys:
@"Red",@"titleValue",
[UIColor redColor],@"colorValue",nil],
[NSDictionary dictionaryWithObjectsAndKeys:
@"Green",@"titleValue",
[UIColor greenColor],@"colorValue",nil],
[NSDictionary dictionaryWithObjectsAndKeys:
@"Blue",@"titleValue",
[UIColor blueColor],@"colorValue",nil],
nil];

[colorList retain];
}
return self;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

return 1;
}

- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {

return [colorList count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *MyIdentifier = @"MyIdentifier";

UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:MyIdentifier];

if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero
reuseIdentifier:MyIdentifier] autorelease];
}

cell.text = [[colorList objectAtIndex:indexPath.row]
objectForKey:@"titleValue"];
cell.textColor = [[colorList objectAtIndex:indexPath.row]
objectForKey:@"colorValue"];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

return cell;
}

There’s nothing new here, but we’ve included it to clarify the rest of our discussion of the navigation controller.

Adding Actions

If you want, you can now move right on to using your navigation controller. Alternatively, you can do some extra work with buttons. Besides the standard navigation controls, you could also add buttons to the navigation bar. This is done through the leftBarButtonItem and the rightBarButtonItem properties of the UINavigation-Item. A left button will replace your back button, while a right button just sits in the usually blank right-hand side of your navigation bar.

As we’ve noted, each view controller is linked to its own navigation item. A view controller can access its navigation item through the navigationItem property at any time.

When you set a button, you must set it to be a UIBarButtonItem object, which you’ll have to create. There are four init methods you can use, as shown in table 15.2. You will probably use the initWithCoder: method, the same place that you should be initializing your array for use with your table view.

Table 15.2. You can create bar button items using a variety of methods to get precisely what you want.

Method

Summary

initWithBarButtonSystemItem:target:action:

Creates a standard button drawn from UIButtonSystemItem

initWithCustomView:

Creates a special button

initWithImage:style:target:action:

Creates a button with a picture

initWithTitle:style:target:action:

Creates a button with a word

Note that all the buttons except for the custom view button come with their own target and action links. These are the simpler target-action mechanisms that we alluded to in the previous chapter. They work exactly like the more complex target-action mechanisms but are built in.

Here’s how you could create a button as part of the page represented by your UITableViewController:

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

As you can guess from our title, this button press just enacts a very innocuous title change, but it would be easy to redraw your table list or even to integrate that button with the navigation itself, perhaps using it as a home button.

At this point you’ve got a navigation controller that does precisely nothing, other than showing a gray bar with a title, and perhaps a working button. Unlike with the other controllers that you’ve met so far, you’re going to need to do some runtime work to get your navigation controller actually working.

15.2.4. Using your navigation controller

A navigation controller has one core job: to allow a user to move up and down through a hierarchy of pages.

Navigating Forward

To allow a user to navigate to a page deeper in your hierarchy, you need to use the navigation controller’s interface to push a new view controller on top of the navigation controller’s stack, which will then cause that new view controller’s view to become the visible view in your program. This is shown in listing 15.3, which continues to expand upon RootViewController.m.

Listing 15.3. Activating a navigation controller

To navigate using tables, you must modify the table view controller’s tableView:didSelectRowAtIndexPath: method , which you first met in chapter 13. Clearly, if you’re activating your navigation controller by some other method, you’ll use different means.

When your users select an item that should lead them to the next page, you’ll have to create the page they’ll be going to. Start off by creating a view controller . Remember to set the title since it’ll be the title that appears in your new view controller’s navigation item. Matching the title to your table cell’s text will probably be a common way to set this property.

Once you’ve created a view controller, you need to decide how to create its default view. Here you’re creating a plain view . Prefer to create your view in Interface Builder? No problem. Just use the initWithNibName: method when you create your view controller, as we discussed in chapter 12.

Each view should have different content based on what your user selected. Here, you’ll be looking at the text color of the table cell’s text and then setting the whole view to that color . More often you’ll probably look up an NSDictionary element from the same array that you used to fill in your table and use that information to generate a unique page. For example, it’d be easy to pull a nib name out of a dictionary.

Once you’ve set up your new page, you just send one message to the navigation controller to switch over to it . Note that you can find a reference to your navigation controller by using the view controller’s navigationController property, another of many object links available in the view controller. The actual push command is simple: it just adds a new page to the top of the navigation controller’s stack, and thus sends your user over to it.

Navigating Backward

Once you’ve loaded a new page onto a navigation controller’s stack, it appears with all the peripherals you’d expect, including a titled navigation bar with a titled back button (each based on the title property of the appropriate controller). This is all shown in figure 15.6.

Figure 15.6. With a few simple commands, a navigation controller’s setup is largely automated.

You also don’t have to worry about coding the backward navigation. Clicking the back bottom will automatically pop the top controller off the stack, without any work on your part.

Other Types of Navigation

Navigation doesn’t have to be just forward and backward. You can also do some slightly more complex things, either during setup or at runtime.

At setup you can choose to create a navigational hierarchy and push a user into it before he or she takes any actions. You can see this in action in various iPhone programs. Mail always returns you to the last mailbox you were at, while Contacts always gives you a back button to return to the “groups” page.

You can do fancy things during runtime using three navigation controller methods: popToRootViewControllerAnimated: (which brings you back to the top of your stack), popToViewController:Animated: (which returns you to a specific view controller), or popViewControllerAnimated: (which just pops the top controller off the stack).

They’re quite powerful, though you have to take care when changing the standard navigation paradigm so that you don’t confuse your users. But, as an example, you could place a UIBarButtonItem in your nav bar that returns you to home from deep in your hierarchy. Alternately, you might pop the top page automatically after a user takes some action on the page that concludes its usefulness.

Navigators and Databases

So far we’ve built all of our table view controllers—including the one embedded in this navigation controller—using arrays. This is a perfectly acceptable technique for a small, static table. But if you want to have a bigger or a more dynamic table, you’ll probably want to use a database as your data back end. We’ll have a complete example of how to do so in chapter 16, when we cover the SQLite database package.

Other Methods and Properties

There’s very little else to be done with the navigation controller, though you’ll find a few other properties in the class reference. You can set those properties to modify the look of individual UIBarButtonItems and to set your nav bar to be hidden.

We’ve now covered the two most important advanced view controllers, but before we finish our discussion of the topic, let’s take a brief look at the flipside controller, which exists only as a template, not as a class within the UIKit framework. The template instead creates a subclass of ViewController within your program.

15.3. Using the flipside controller

To create a flipside controller, choose the Utility Application template when you start a new project. It will create a small hierarchy of objects, as shown in figure 15.7.

Figure 15.7. Several objects are created in a flipside controller.

The flipside controller contains three view controllers and two views. Each of the view controllers is a subclass of UIViewController, while the views are each a subclass of UIView.

The main view controller is called the Root-ViewController. It’s loaded through Main-Window.xib. Much of the template’s work is done, as you’d expect, through its class files. The RootViewController.m file loads the MainViewController (using the initWithNibName: method to load its unique nib file), and then creates a special toggleView method for when the info button at the bottom of the page is pushed. When this happens, the FlipsideViewController also loads. Listing 15.4 shows this standard method, which you shouldn’t have to modify at all.

Listing 15.4. The flipside toggler
- (IBAction)toggleView {

if (flipsideViewController == nil) {
[self loadFlipsideViewController];
}
UIView *mainView = mainViewController.view;
UIView *flipsideView = flipsideViewController.view;

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1];
[UIView setAnimationTransition:([mainView superview] ?
UIViewAnimationTransitionFlipFromRight :
UIViewAnimationTransitionFlipFromLeft) forView:self.view
cache:YES];

if ([mainView superview] != nil) {
[flipsideViewController viewWillAppear:YES];
[mainViewController viewWillDisappear:YES];
[mainView removeFromSuperview];
[infoButton removeFromSuperview];
[self.view addSubview:flipsideView];
[self.view insertSubview:flipsideNavigationBar
aboveSubview:flipsideView];
[mainViewController viewDidDisappear:YES];
[flipsideViewController viewDidAppear:YES];
} else {
[mainViewController viewWillAppear:YES];

[flipsideViewController viewWillDisappear:YES];
[flipsideView removeFromSuperview];
[flipsideNavigationBar removeFromSuperview];
[self.view addSubview:mainView];
[self.view insertSubview:infoButton
aboveSubview:mainViewController.view];
[flipsideViewController viewDidDisappear:YES];
[mainViewController viewDidAppear:YES];
}
[UIView commitAnimations];
}

Because you shouldn’t need to modify it, we’re not going to cover all of this code, but if you read through it, you’ll find that it includes some nice nuances, including the ability to work with UIView’s simple animation and some different ways to call insertSubview:. This template provides a great example of how to connect multiple Xcode class files and multiple nib files, and reading through it can serve as a great tutorial for more advanced work you’re going to do yourself.

For example, take a look at the MainWindow.xib file. You’ll note there that connections are made to two different files, as shown in figure 15.8. The app delegate file contains a link to the root view controller object, while the root view controller file contains links to the info button object and its action. This shows the sort of organization you’ll want to consider for you own projects.

Figure 15.8. Objects in Interface Builder can connect to a variety of different files.

Given that, how do you actually use the flipside controller? All you need to do is lay out objects in the two .xib files and/or make changes to their accompanying class files. Then you can build controller actions, events, and other activities into the two controller files.

For example, you could use Interface Builder to make your main view red; then you could go into the FlipsideViewController.m file and change the default background color to greenColor (instead of its current flipsideColor) to create a simple red and green flash card, which can be used to express your interest in a conference topic. We’ll also show how to use a flipside controller to create local preferences on the backside of your program in chapter 16. If you ever need a two-sided application, the flipside controller is a great place to get started.

So far we’ve explored those view controllers that you might use as the building blocks of your own views. Tab bars, navigators, and flipsides are ultimately tools that you’ll use to construct other sorts of programs. However, there’s a different type of view controller that exists to accomplish very specific tasks: the modal view controller.

15.4. Modal view controllers

Technically, a modal view refers to a temporary view that’s placed on top of all of the elements of an existing view and then later dismissed. A modal view controller is a view controller that manages such a modal view.

Practically, the modal views already available in the iPhone OS are all “helper” programs, which allow you to start up a complex graphical interface that’s been preprogrammed by Apple while only managing the responses. You get the advantage of lots of programming (and a standardized interface), and you don’t have to do much yourself.

Whenever you want to display a modal view, you use the UIViewController’s presentModalViewController:animated: method to start it up:

[self presentModalViewController:myPicker animated:YES];

Later you’ll dismiss it using another UIViewController method:

[self dismissModalViewControllerAnimated:YES];

You could design your own modal view controllers for when you want to have users make a choice before returning them to their regular program. More commonly, you’ll use picker controllers that are intended to be run as modal view controllers. In chapter 16 you’ll meet the Address Book UI people picker (as well as some related controllers that run inside a navigator), and then in chapter 18 you’ll meet the image picker.

15.5. Summary

At this point we’ve finished with what we consider our basic introduction to the SDK. Since this is an introductory SDK book, it’s been our main goal to show you all the fundamentals before we set you lose in the wilds of iPhone programming so that you have the building blocks that you need when you begin programming on your own.

To briefly review them all:

  • The SDK is built on top of Objective-C and is supported by a large set of frameworks called the iPhone OS. (See chapter 10.)
  • Programming can be done in either Xcode or Interface Builder, supporting two powerful ways to create objects. (See chapters 11 and 12.)
  • Basic view controllers take the controller role of the MVC model and allow you to administer your views in a rational way. (See chapter 13.)
  • Events provide low-level methods for seeing what a user is doing, while actions provide more sophisticated connections to buttons, sliders, text fields, and other tools. (See chapter 14.)
  • Advanced view controllers provide you with a variety of ways to navigate among pages. (See chapter 15.)

Although we’ve completed our introduction to the iPhone SDK, we’re not done yet. We’re going to finish this book by looking at some of the neat tools that are available inside the SDK, including a look at internet-related tools, bringing us full circle to the web techniques that opened this book. Our first stop, however, is an in-depth look at the many ways to input data into an iPhone program.

 

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset