We have all seen this many times. Now we are going to code it!
How does this work? It uses a class named UINavigationController. This class is similar to the tab bar controller we learned about in week 6. Instead of a group of tab buttons a navigation controller uses a stack of view controllers.
Here’s how it works.
We start with a navigation controller and one table view controller.
The user taps on a row in the table view.
A new view controller is created.
The new view controller is added to the navigation controller’s array of controllers.
The new view controller is then animated over the top of the first view controller. The is called pushing the new controller to the top of the stack of controllers.
The new view controller covers the root controller. It is shown offset a bit in this illustration to show that the root controller is still there behind the new controller.
Next, the user taps on the button to return to the previous view.
The second view slides off of the root view in an animation. This is called popping the controller off the stack of controllers.
Once the view controller is fully off the screen it is removed from the stack of controllers and deleted.
Add a UINavigationController to Homepwner
How do we add a navigation controller? With a little code, of course!
Open a new copy of your Homepwner app and go to the HomepwnerAppDelegate.m file. Here’s what we have now.
We already have the table view controller that will be the root for the navigation controller. We need to create the instance of UINavigationController first with this code.
Notice that we use the itemsViewController as the root for the navigation controller.
Next, we make the navigation controller the root of the window.
The whole method is now this.
That’s it. We added one line of code and changed another one. Run the app and see what happens.
The only change we see is the navigation bar at the top of the screen. This is an instance of UINavigationBar and is part of the navigation controller.
Next we add the second view controller.
An Additional UIViewController
Create a new Objective-C class. Name it DetailViewController, subclass UIViewController, and check the box to make a nib file.
That will create three files.
The DetailViewController.m file no longer has too much code generated by Xcode so there is no reason to delete all the implementation code.
Open the DetailViewController.xib file and uncheck the Autolayout checkbox.
Then add the UI elements shown here.
Option-click on the DetailViewController.m and add four outlets to the class extension. The outlets are the three text field and the bottom label.
Your class extension should look like this with the connection circles filled in.
Next, we need to connect the delegate for each of the text fields to the File’s Owner. Control-click on a text field, then click-and-drag to the File’s Owner.
Repeat this for all three text fields.
Open the DetailViewController.m file and edit the viewDidLoad method.
This will set the background color of the detail view to match the table view.
Navigating with UINavigationController
Now we get to the fun part! Let’s make it work. Open the ItemsViewController.m file.
Pushing view controllers
When the user taps on a row what happens?
We need to create a DetailViewController and push it on the stack of controllers. The method that runs when a user taps on a row is this.
First, we have to make the controller.
Don’t forget to #import "DetailViewController.h"
Now we need to push the detail controller on top of the controller stack.
The full method in ItemsViewController.m
Run the app. Create a few rows and then tap on one of the items. The detail view will slide from the right.
Now tap on the Back button and the detail view will slide back to the right.
(Except there’s no data in the detail view. We’ll fix that next.)
Passing data between view controllers
The detail view will show the data from one BNRItem. We can also edit the data.
The first thing we need to do is have the DetailViewController class have a place to hold one BNRItem. We’ll do this with a property. This needs to be a public property so we declare it in the DetailViewController.h file.
We need the @class, too.
Switch to the DetailViewController.m file and first import BNRItem.h.
(Note: There’s no need to @synthesize properties anymore.)
Remember the method that runs whenever a view controller appears? Yup, it’s viewWillAppear:. In this method we will set the data from our BNRItem into the text properties of our UI outlets.
Next we need to actually have a BNRItem in the property for this to work.
Switch to the ItemsViewController.m file and add the highlighted code to this method.
Run the app, add some items, then tap on one.
Woo! We have data.
Tap the Back button and tap on another row. The data should show the new row.
We’re getting closer!
Next we have to save any changes we make in the detail view back into the BNRItem.
Appearing and disappearing views
When the detail view slides back to the right the message viewWillDisappear: will get sent to it.
We’ll get the text from our text fields and assign the values back into our BNRItem.
We’re not quite done. Notice that when you change something like the Value…
And return to the list, the new value doesn’t change.
That happens because the table view doesn’t automatically refresh its data. This is done to save CPU time which takes time and battery power. In order for the table view to be refreshed we have to ask it to update. We do this in the viewWillAppear: method. Add this to the ItemsViewController.m file.
Sending the message reloadData to the table view does the trick.
Run the app, add some rows, tap on one of them, edit something, tap the Back button. The data is changed. Cool!
What’s next? We need to fix this.
Yup, we need to start using the UINavigationBar that’s just siting there doing nothing.
We’ll start with the title. Modify the init method in ItemsViewController.m to be this.
The navigation bar gets it title from the UINavigationItem of the controller. Each view controller that is shown by a navigation controller has to set its own title. The navigation bar picks this up when it shows the view controller.
Run the app and you should see the title.
Tap on a row to go to the detail page.
The navigation controller automatically uses the title of the previous controller as the button title. Cool, eh?
Now let’s set the title of the detail controller page. This view should have a title that reflects the content of the page. We’re going to use a nice feature of Object-Orientation. We will write our own set method for the BNRItem that the DetailViewController holds. We already have the property.
That code causes a method to be generated named setItem:. If we write that method ourselves then the generator will not create one. Add this method to DetailViewController.m.
I think you can see what it’s doing. When the item gets set in ItemsViewController.m the title also gets set. Run the app, add some rows, tap on a row, see the title of the detail view!
The Edit and New buttons belong in the navigation bar. Let’s start with New. Modify the init method in ItemsViewController.m.
Run the app and now we are looking more professional.
How about the Edit button? That’s really easy. Just add one line of code to the init method.
That’s it? Yup! The editing function is built in. We just have to add that button.
Now we have to remove all the code that made the first Edit and New buttons. Comment all the following code. We’ll leave it in the project because we might want something like it in the future.