Click anywhere on a view to go to the next one.
The status and navigation bars, not to mention the back button and the leading between the lines of text, looked better in iOS 6. What were they thinking of?
The tab bar controller we saw here let us visit the view controllers in any order. A navigation controller lets us visit the view controllers in only one specific order: Eighth Avenue, Sixth Avenue, Union Square, etc., and back again. You can’t jump directly from Eighth Avenue to Union Square without visiting Sixth Avenue along the way. See Bars and Navigation Bars.
The classic example of a
navigation controller
is in the
Settings
app that comes with the iPhone.
The navigation controller provides the
right-to-left animation as we drill deeper into the menus,
and left-to-right animation as we come back out.
It does not provide the menus themselves—they will come later,
when we have class
UITableView
.
If the navigation bar has no room for the title and the back button,
hold the iPhone in landscape orientation.
Even if we have only one view controller and one view, we might still want to put a navigation controller atop the view controller just to see the view controller’s navigation bar. Every view controller has a navigation bar, but the navigation bar is visible only if there is a navigation controller above the view controller. The navigation bar can have attractive titles and buttons.
The
NavigateAppDelegate
creates the
UINavigationController
and puts it in the
window.
The
UINavigationController
contains one or more
ViewController
s,
one for each station on the L Train,
Manhattan’s only east/west subway line.
Each
ViewController
contains one
View
.
The
application:didFinishLaunchingWithOptions:
NavigateAppDelgate
creates only the first
ViewController
,
not all of them,
because it might be expensive to create objects of this class.
We create the
ViewController
s
only as needed.
main.m
NavigateAppDelegate
ViewController
View
It would be possible for a lowly
view
to talk directly to the
application
delegate.
For example, the
touchesEnded:withEvent:
View
could be changed to the following.
- (void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event { UIApplication *application = [UIApplication sharedApplication]; NavigateAppDelegate *applicationDelegate = application.delegate; [applicationDelegate nextStation]; }To mention class
NavigateAppDelegate
in the file
View.m
,
we would have to say
#import "NavigateAppDelegate.h"at the top of
View.m
.
But please resist this temptation. Instead of talking to objects all over the application, a view should restrict itself to talking to its view controller. The view controller can then talk to the model on behalf of the view. In our case, the model consists of the array of stations in the application delegate and the number of currently pushed stations.
initWithFrame:
method of class
View
,
change the background color to the following.
The expression
(CGFloat)rand() / RAND_MAX
CGFloat
because all-integer division would result in an integer quotient,
not a fraction.
self.backgroundColor = [UIColor colorWithRed: (CGFloat)rand() / RAND_MAX green: (CGFloat)rand() / RAND_MAX blue: 1.0 alpha: 1.0 ];To get different random colors each time you run the app, insert the following code at the start of the
application:didFinishLaunchingWithOptions:
NavigateAppDelegate
.
//Seed the random number generator with a different seed //each time the app is run. srand(time(NULL));
nextStation
NavigateAppDelegate
,
what happens if you change the
animated:
NO
?
title
of the controller that is currently displayed by the navigation controller.
To add a prompt to the top of the navigation bar
(occcupying an additional 30 pixels),
insert the following statement into the
initWithTitle:
ViewController
after setting the
title
.
self.navigationItem.prompt = [NSString stringWithFormat: @"Welcome to %@.", self.title];I acknowledge that this prompt is inane.
initWithTitle:
ViewController
after setting the
title
and
prompt
.
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle: @"Go East" style: UIBarButtonItemStylePlain target: self action: @selector(nextStation) ];You can now remove
touchesEnded:withEvent:
View
.
How could you prevent the last station (First Avenue) from having the
“Go East” button?
toolbarhidden
property of the
UINavigationController
to
NO
.
((UINavigationController *)self.window.rootViewController).toolbarHidden = NO;The tool bar that appears at the bottom of the screen will be empty. We will use a tool bar here.
ViewController
each time we retreat one station to the west,
and re-create it each time we advance one station to the east.
We can verify this by adding the following method to class
ViewController
.
- (void) dealloc { NSLog(@"ViewController %@ is being destroyed", self.title); }It would save time if we could create the
ViewController
the first time we visit it,
and keep it stored in an array in case we visit it again in the future.
Give the application delegate the following instance variable.
//all the stations we have already visited at any time NSMutableArray *visited;Initialize the instance variable in
application:didFinishLaunchingWithOptions:
.
visited = [NSMutableArray arrayWithObject: firstController];Change the
nextStation
method of the application delegate to the following.
- (void) nextStation { UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController; NSUInteger i = navigationController.viewControllers.count; if (i == titles.count) { //We are currently visiting the last station, and can go no farther. return; } if (visited.count <= i) { //This station is being visited for the first time. NSString *title = [titles objectAtIndex: i]; ViewController *viewController = [[ViewController alloc] initWithTitle: title]; [visited addObject: viewController]; } [navigationController pushViewController: [visited objectAtIndex: i] animated: YES]; }