12
UINavigationController

In Chapter 7, you learned about UITabBarController and how it allows a user to access different screens. A tab bar controller is great when you have screens that don’t rely on each other, but what if you want to move between related screens?

For example, the Settings application has multiple related screens of information: a list of settings (like Sounds), a detailed page for each setting, and a selection page for each detail. This type of interface is called a drill-down interface.

In this chapter, you will use a UINavigationController to add a drill-down interface to Homepwner that lets the user view and edit the details of a Possession. (Figure 12.1).

Figure 12.1  Homepwner with UINavigationController

Homepwner with UINavigationController

UINavigationController

When your application presents multiple screens of information, UINavigationController maintains a stack of those screens. The stack is an NSArray of view controllers, and each screen is the view of a UIViewController. When a UIViewController is on top of the stack, its view is visible.

When you initialize an instance of UINavigationController, you give it one UIViewController. This UIViewController is called the root view controller. The root view controller is always on the bottom of the stack (which is also the top if there is only one item). Figure 12.2 shows a navigation controller with two view controllers: a root view controller and an additional view controller above it at the top of the stack. The additional view controller is the one the user sees. When the UIViewController is pushed onto the stack, its view slides onto the screen from the right. When the stack is popped, the top view controller is removed from the stack, and the view of the one below it slides onto the screen from the left.

Figure 12.2  UINavigationController’s stack

UINavigationController’s stack

More view controllers can be pushed on top of the UINavigationController’s stack during execution. This ability to add to the stack during execution is missing in UITabBarController, which gets all of its view controllers when it is initialized. With a navigation controller, only the root view controller is guaranteed to always be in the stack.

The UIViewController that is currently on top of the stack is accessed by sending the message topViewController to the UINavigationController instance. You can also get the entire stack as an NSArray by sending the navigation controller the message viewControllers. The viewControllers array is ordered so that the root view controller is the first entry and the top view controller is the last entry.

UINavigationController is a also subclass of UIViewController, so it has a view of its own. Its view always has at least two subviews: a UINavigationBar and the view of its topViewController (Figure 12.3).

Figure 12.3  A UINavigationController’s view

A UINavigationController’s view

In this chapter, you will add a UINavigationController to the Homepwner application and make the ItemsViewController the UINavigationController’s rootViewController. Then, you will create another subclass of UIViewController that can be pushed onto the UINavigationController’s stack. When a user selects one of the possession rows, the new UIViewController’s view will slide onto the screen. This view controller will allow the user to view and edit the properties of the selected Possession. The object diagram for the updated Homepwner application is shown in Figure 12.4.

Figure 12.4  Homepwner object diagram

Homepwner object diagram

This application is getting fairly large, as you can see in the massive object diagram. Fortunately, view controllers and UINavigationController know how to deal with this type of complicated object diagram. When writing iOS applications, it is important to treat each UIViewController as its own little world. The stuff that has already been implemented in Cocoa Touch will do the heavy lifting.

Now let’s give Homepwner a navigation controller. Reopen the Homepwner project and then open HomepwnerAppDelegate.m. The only requirements for using a UINavigationController are that you give it a root view controller and add its view to the visible view hierarchy. In application:​didFinishLaunchingWithOptions:, create the UINavigationController, give it a root view controller of its own, and set the UINavigationController as the root view controller of the window.

-​ ​(​B​O​O​L​)​a​p​p​l​i​c​a​t​i​o​n​:​(​U​I​A​p​p​l​i​c​a​t​i​o​n​ ​*​)​a​p​p​l​i​c​a​t​i​o​n​
 ​ ​ ​ ​d​i​d​F​i​n​i​s​h​L​a​u​n​c​h​i​n​g​W​i​t​h​O​p​t​i​o​n​s​:​(​N​S​D​i​c​t​i​o​n​a​r​y​ ​*​)​l​a​u​n​c​h​O​p​t​i​o​n​s​
{​
 ​ ​ ​ ​I​t​e​m​s​V​i​e​w​C​o​n​t​r​o​l​l​e​r​ ​*​i​t​e​m​s​V​i​e​w​C​o​n​t​r​o​l​l​e​r​ ​=​ ​[​[​I​t​e​m​s​V​i​e​w​C​o​n​t​r​o​l​l​e​r​ ​a​l​l​o​c​]​ ​i​n​i​t​]​;​


 ​ ​ ​ ​/​/​ ​C​r​e​a​t​e​ ​a​n​ ​i​n​s​t​a​n​c​e​ ​o​f​ ​a​ ​U​I​N​a​v​i​g​a​t​i​o​n​C​o​n​t​r​o​l​l​e​r​
 ​ ​ ​ ​/​/​ ​i​t​s​ ​s​t​a​c​k​ ​c​o​n​t​a​i​n​s​ ​o​n​l​y​ ​i​t​e​m​s​V​i​e​w​C​o​n​t​r​o​l​l​e​r​
 ​ ​ ​ ​U​I​N​a​v​i​g​a​t​i​o​n​C​o​n​t​r​o​l​l​e​r​ ​*​n​a​v​C​o​n​t​r​o​l​l​e​r​ ​=​ ​[​[​U​I​N​a​v​i​g​a​t​i​o​n​C​o​n​t​r​o​l​l​e​r​ ​a​l​l​o​c​]​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​i​n​i​t​W​i​t​h​R​o​o​t​V​i​e​w​C​o​n​t​r​o​l​l​e​r​:​i​t​e​m​s​V​i​e​w​C​o​n​t​r​o​l​l​e​r​]​;​

 ​ ​ ​ ​/​/​ ​Y​o​u​ ​c​a​n​ ​n​o​w​ ​r​e​l​e​a​s​e​ ​t​h​e​ ​i​t​e​m​s​V​i​e​w​C​o​n​t​r​o​l​l​e​r​ ​h​e​r​e​,​
 ​ ​ ​ ​/​/​ ​U​I​N​a​v​i​g​a​t​i​o​n​C​o​n​t​r​o​l​l​e​r​ ​w​i​l​l​ ​r​e​t​a​i​n​ ​i​t​
 ​ ​ ​ ​[​i​t​e​m​s​V​i​e​w​C​o​n​t​r​o​l​l​e​r​ ​r​e​l​e​a​s​e​]​;​

 ​ ​ ​ ​/​/​ ​P​l​a​c​e​ ​n​a​v​i​g​a​t​i​o​n​ ​c​o​n​t​r​o​l​l​e​r​'​s​ ​v​i​e​w​ ​i​n​ ​t​h​e​ ​w​i​n​d​o​w​ ​h​i​e​r​a​r​c​h​y​
 ​ ​ ​ ​[​[​s​e​l​f​ ​w​i​n​d​o​w​]​ ​s​e​t​R​o​o​t​V​i​e​w​C​o​n​t​r​o​l​l​e​r​:​n​a​v​C​o​n​t​r​o​l​l​e​r​]​;​

 ​ ​ ​ ​[​n​a​v​C​o​n​t​r​o​l​l​e​r​ ​r​e​l​e​a​s​e​]​;​


 ​ ​ ​ ​[​[​s​e​l​f​ ​w​i​n​d​o​w​]​ ​m​a​k​e​K​e​y​A​n​d​V​i​s​i​b​l​e​]​;​
 ​ ​ ​ ​r​e​t​u​r​n​ ​Y​E​S​;​
}​

This code initializes the UINavigationController instance with ItemsViewController as its root view controller and makes the UINavigationController the rootViewController of the window. Becoming the window’s rootViewController places the navigation controller’s view in the view hierarchy.

Build and run the application. Homepwner will look the same as it did before – except now it has a UINavigationBar at the top of the screen (Figure 12.5). Notice how ItemsViewController’s view was resized to fit the screen with a navigation bar. UINavigationController did this for you.

Figure 12.5  Homepwner with an empty navigation bar

Homepwner with an empty navigation bar

UINavigationBar

The UINavigationBar isn’t very interesting right now. At a minimum, a UINavigationBar should display a descriptive title for the UIViewController that is currently on top of the UINavigationController’s stack.

Every UIViewController has a navigationItem property of type UINavigationItem. However, unlike UINavigationBar, UINavigationItem is not a subclass of UIView, so it cannot appear on the screen. Instead, the navigation item supplies the navigation bar with the content it needs to draw. When a UIViewController comes to the top of a UINavigationController’s stack, the UINavigationBar uses the UIViewController’s navigationItem to configure itself, as shown in Figure 12.6.

Figure 12.6  UINavigationItem

UINavigationItem

That’s not the easiest thing to understand at first glance. So, consider the following analogy. Think of a UIViewController as an NFL football team, and moving to the top of the stack as going to the Super Bowl. The UINavigationItem is the team logo design, which is the property of the team and, no matter what happens, remains unchanged. The UINavigationController is the stadium, and the UINavigationBar is an end zone. In a similar manner, when a UIViewController is moved to the top of the stack, its UINavigationItem is painted on the UINavigationBar of the UINavigationController.

By default, a UINavigationItem is empty. At the most basic level, a UINavigationItem has a simple title string. When a UIViewController is moved to the top of the navigation stack and its navigationItem has a valid string for its title property, the navigation bar will display that string (Figure 12.7).

Figure 12.7  UINavigationItem with title

UINavigationItem with title

A navigation item can hold more than just a title string, as shown in Figure 12.8. There are three customizable areas for each UINavigationItem: a leftBarButtonItem, a rightBarButtonItem, and a titleView. The left and right bar button items are pointers to instances of UIBarButtonItem, which contains the information for a button that can only be displayed on a UINavigationBar or a UIToolbar.

Figure 12.8  UINavigationItem with everything

UINavigationItem with everything

Like UINavigationItem, UIBarButtonItem is not a subclass of UIView but supplies the content that a UINavigationBar needs to draw. Consider the UINavigationItem and its UIBarButtonItems to be containers for strings, images, and other content. A UINavigationBar knows how to look in those containers and draw the content it finds.

The third customizable area of a UINavigationItem is its titleView. You can either use a basic string as the title or have a subclass of UIView sit in the center of the navigation item. You cannot have both. If it suits the context of a specific view controller to have a custom view (like a button, a slider, an image, or even a map), you would set the titleView of the navigation item to that custom view. Figure 12.8 shows an example of a UINavigationItem with a custom view as its titleView. Typically, however, a title string is sufficient, and that’s what we’ll do in this chapter.

Now let’s give Homepwner a UINavigationBar it can be proud of. In ItemsViewController.m, create a UIBarButtonItem instance. This button will sit on the right side of the navigation bar when the ItemsViewController is on top of the stack. When tapped, it will add a new Possession to the list. Also, set the navigation item’s title. This string will be displayed in the center of the navigation bar.

-​ ​(​i​d​)​i​n​i​t​
{​
 ​ ​ ​ ​s​e​l​f​ ​=​ ​[​s​u​p​e​r​ ​i​n​i​t​W​i​t​h​S​t​y​l​e​:​U​I​T​a​b​l​e​V​i​e​w​S​t​y​l​e​G​r​o​u​p​e​d​]​;​

 ​ ​ ​ ​i​f​ ​(​s​e​l​f​)​ ​{​
 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​C​r​e​a​t​e​ ​a​ ​n​e​w​ ​b​a​r​ ​b​u​t​t​o​n​ ​i​t​e​m​ ​t​h​a​t​ ​w​i​l​l​ ​s​e​n​d​
 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​a​d​d​N​e​w​P​o​s​s​e​s​s​i​o​n​:​ ​t​o​ ​I​t​e​m​s​V​i​e​w​C​o​n​t​r​o​l​l​e​r​
 ​ ​ ​ ​ ​ ​ ​ ​U​I​B​a​r​B​u​t​t​o​n​I​t​e​m​ ​*​b​b​i​ ​=​ ​[​[​U​I​B​a​r​B​u​t​t​o​n​I​t​e​m​ ​a​l​l​o​c​]​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​i​n​i​t​W​i​t​h​B​a​r​B​u​t​t​o​n​S​y​s​t​e​m​I​t​e​m​:​U​I​B​a​r​B​u​t​t​o​n​S​y​s​t​e​m​I​t​e​m​A​d​d​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​t​a​r​g​e​t​:​s​e​l​f​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​a​c​t​i​o​n​:​@​s​e​l​e​c​t​o​r​(​a​d​d​N​e​w​P​o​s​s​e​s​s​i​o​n​:​)​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​S​e​t​ ​t​h​i​s​ ​b​a​r​ ​b​u​t​t​o​n​ ​i​t​e​m​ ​a​s​ ​t​h​e​ ​r​i​g​h​t​ ​i​t​e​m​ ​i​n​ ​t​h​e​ ​n​a​v​i​g​a​t​i​o​n​I​t​e​m​
 ​ ​ ​ ​ ​ ​ ​ ​[​[​s​e​l​f​ ​n​a​v​i​g​a​t​i​o​n​I​t​e​m​]​ ​s​e​t​R​i​g​h​t​B​a​r​B​u​t​t​o​n​I​t​e​m​:​b​b​i​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​T​h​e​ ​n​a​v​i​g​a​t​i​o​n​I​t​e​m​ ​r​e​t​a​i​n​s​ ​i​t​s​ ​b​u​t​t​o​n​s​,​ ​s​o​ ​b​b​i​ ​c​a​n​ ​b​e​ ​r​e​l​e​a​s​e​d​
 ​ ​ ​ ​ ​ ​ ​ ​[​b​b​i​ ​r​e​l​e​a​s​e​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​S​e​t​ ​t​h​e​ ​t​i​t​l​e​ ​o​f​ ​t​h​e​ ​n​a​v​i​g​a​t​i​o​n​ ​i​t​e​m​
 ​ ​ ​ ​ ​ ​ ​ ​[​[​s​e​l​f​ ​n​a​v​i​g​a​t​i​o​n​I​t​e​m​]​ ​s​e​t​T​i​t​l​e​:​@​"​H​o​m​e​p​w​n​e​r​"​]​;​
 ​ ​ ​ ​}​
 ​ ​ ​ ​r​e​t​u​r​n​ ​s​e​l​f​;​
}​

Build and run the application. Tap the + button, and a new row will appear in the table. (Note that this is not the only way to set up a bar button item; check the documentation for other initialization messages you can send an instance of UIBarButtonItem.)

A bar button item has a target-action pair that works like UIControl’s target-action mechanism: when tapped, it sends the action message to the target. When you set a target-action pair in a XIB file, you Control-drag from a button to its target and then select a method from the list of IBActions. To programmatically set up a target-action pair, you pass the target and the action to the button. The action is passed as a value of type SEL.

The SEL data type is a pointer to a selector. A selector is a unique ID for a method. Wrapping a method name in the @selector() directive returns the SEL that points at that method. Remember that a selector is the entire method name including any colons. Here are some examples of method declarations and how you would wrap them in @selector():

-​ ​(​v​o​i​d​)​m​e​t​h​o​d​;​
-​ ​(​i​n​t​)​m​e​t​h​o​d​W​i​t​h​A​r​g​:​(​i​d​)​a​r​g​1​;​
-​ ​(​B​O​O​L​)​m​e​t​h​o​d​W​i​t​h​A​r​g​:​(​i​d​)​a​r​g​1​ ​a​n​d​A​n​o​t​h​e​r​A​r​g​:​(​i​d​)​a​r​g​2​;​

S​E​L​ ​m​1​ ​=​ ​@​s​e​l​e​c​t​o​r​(​m​e​t​h​o​d​)​;​
S​E​L​ ​m​2​ ​=​ ​@​s​e​l​e​c​t​o​r​(​m​e​t​h​o​d​W​i​t​h​A​r​g​:​)​;​
S​E​L​ ​m​3​ ​=​ ​@​s​e​l​e​c​t​o​r​(​m​e​t​h​o​d​W​i​t​h​A​r​g​:​a​n​d​A​n​o​t​h​e​r​A​r​g​:​)​;​

Notice that @selector() doesn’t care about the return type, argument types, or names of arguments – only the selector itself. Also, know that @selector() doesn’t check to see if the method actually exists. If you give a SEL to a button, that button will send the corresponding message regardless of whether the method is implemented by the target.

Now you’re going to replace the Edit button in the table view header with a UIBarButtonItem. In ItemsViewController.m, edit the init method.

-​ ​(​i​d​)​i​n​i​t​
{​
 ​ ​ ​ ​s​e​l​f​ ​=​ ​[​s​u​p​e​r​ ​i​n​i​t​W​i​t​h​S​t​y​l​e​:​U​I​T​a​b​l​e​V​i​e​w​S​t​y​l​e​G​r​o​u​p​e​d​]​;​

 ​ ​ ​ ​i​f​ ​(​s​e​l​f​)​ ​{​
 ​ ​ ​ ​ ​ ​ ​ ​U​I​B​a​r​B​u​t​t​o​n​I​t​e​m​ ​*​b​b​i​ ​=​ ​[​[​U​I​B​a​r​B​u​t​t​o​n​I​t​e​m​ ​a​l​l​o​c​]​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​i​n​i​t​W​i​t​h​B​a​r​B​u​t​t​o​n​S​y​s​t​e​m​I​t​e​m​:​U​I​B​a​r​B​u​t​t​o​n​S​y​s​t​e​m​I​t​e​m​A​d​d​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​t​a​r​g​e​t​:​s​e​l​f​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​a​c​t​i​o​n​:​@​s​e​l​e​c​t​o​r​(​a​d​d​N​e​w​P​o​s​s​e​s​s​i​o​n​:​)​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​[​[​s​e​l​f​ ​n​a​v​i​g​a​t​i​o​n​I​t​e​m​]​ ​s​e​t​R​i​g​h​t​B​a​r​B​u​t​t​o​n​I​t​e​m​:​b​b​i​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​[​b​b​i​ ​r​e​l​e​a​s​e​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​[​[​s​e​l​f​ ​n​a​v​i​g​a​t​i​o​n​I​t​e​m​]​ ​s​e​t​T​i​t​l​e​:​@​"​H​o​m​e​p​w​n​e​r​"​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​[​[​s​e​l​f​ ​n​a​v​i​g​a​t​i​o​n​I​t​e​m​]​ ​s​e​t​L​e​f​t​B​a​r​B​u​t​t​o​n​I​t​e​m​:​[​s​e​l​f​ ​e​d​i​t​B​u​t​t​o​n​I​t​e​m​]​]​;​
 ​ ​ ​ ​}​
 ​ ​ ​ ​r​e​t​u​r​n​ ​s​e​l​f​;​
}​

Surprisingly, that’s all the code you need to get an edit button on the navigation bar. Build and run, tap the Edit button, and watch the UITableView enter editing mode! Where does editButtonItem come from? UIViewController has an editButtonItem property, and when sent editButtonItem, the view controller creates a UIBarButtonItem with the title Edit. Even better, this button comes with a target-action pair: it sends the message setEditing:animated: to its UIViewController when tapped.

Now that Homepwner has a fully functional navigation bar, you can get rid of the header view. In ItemsViewController.m, delete the following two methods.

/​/​ ​D​e​l​e​t​e​ ​t​h​e​s​e​!​

-​ ​(​U​I​V​i​e​w​ ​*​)​t​a​b​l​e​V​i​e​w​:​(​U​I​T​a​b​l​e​V​i​e​w​ ​*​)​a​T​a​b​l​e​V​i​e​w​
 ​ ​ ​ ​v​i​e​w​F​o​r​H​e​a​d​e​r​I​n​S​e​c​t​i​o​n​:​(​N​S​I​n​t​e​g​e​r​)​s​e​c​t​i​o​n​
{​
 ​ ​ ​ ​r​e​t​u​r​n​ ​[​s​e​l​f​ ​h​e​a​d​e​r​V​i​e​w​]​;​
}​

-​ ​(​C​G​F​l​o​a​t​)​t​a​b​l​e​V​i​e​w​:​(​U​I​T​a​b​l​e​V​i​e​w​ ​*​)​t​a​b​l​e​V​i​e​w​
 ​ ​ ​ ​h​e​i​g​h​t​F​o​r​H​e​a​d​e​r​I​n​S​e​c​t​i​o​n​:​(​N​S​I​n​t​e​g​e​r​)​s​e​c​t​i​o​n​
{​
 ​ ​ ​ ​r​e​t​u​r​n​ ​[​[​s​e​l​f​ ​h​e​a​d​e​r​V​i​e​w​]​ ​f​r​a​m​e​]​.​s​i​z​e​.​h​e​i​g​h​t​;​
}​

Also remove the instance variable headerView along with the implementation of the methods headerView and toggleEditingMode:.

Now you can build and run again. The old Edit and New buttons are gone, leaving you with a lovely UINavigationBar (Figure 12.9).

Figure 12.9  Homepwner with navigation bar

Homepwner with navigation bar
..................Content has been hidden....................

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