Although you usually want to pop to the previous view
controller upon hitting the Back button, be aware that there are times
you want to pop the entire stack instead. For example, you might have
just given an interactive quiz, or a museum visitor might have finished
his walking tour. For these cases, it makes little sense to move back up
a long complex tree a screen at a time. Instead, use popToRootViewControllerAnimated:. This empties the stack, popping all view controllers except the root, updating the display accordingly.
To pop back to a specific controller other than the root, use popToViewController: animated:. This pops the stack until the top view matches the view controller specified. To pop back just one item, as if the user had tapped the back button, use popViewControllerAnimated:.
Loading a View Controller Array
You can create and assign an array of UIViewController objects to a UINavigationController’s viewControllers
property. The array represents the current controller stack. The top
(that is, active) view controller occupies the last position (n -1) in the array; the root object lives at index 0.
There are various
reasons you might want to set the array property. Controller arrays help
restore previous states after quitting and then returning to an
application. You might store a state list to user defaults and then
re-create the same array on launch, returning your user to the same
place in the controller hierarchy that he or she left from.
Arrays are also handy
when jumping within a conceptual tree. For example, you might be
navigating directories and then need to jump through a symbolic link to
somewhere else. By setting the entire array, you avoid the detail work
of popping and then pushing the stack.
Pushing Momentary Views
Every now and then, I run
into developers who want to be able to push UIViewControllers that do
not remain in the navigation controller stack. For example, you might
start at view 1, push on view 2, and then push on view 3 while letting
the Back button from view 3 link back to the first view.
This situation comes
up more often than you might imagine. The most common reason is that
you’re introducing the action that will take place in the third view
with the second. Typically, the second screen contains instructions,
general “read me” content, or a visual splash. These are meant to
display once and then be gone from the user experience and yet, you want
the navigation controller experience to remain as standard as possible.
To make this work, the Back button needs to ignore the second,
temporary view.
Recipe 1
demonstrates how to do this. When the second view is ready to
transition to the third, the navigation controller goes ahead and
performs the push. This creates the proper animation for the viewer,
from view two to view three. Then, without animation, the code pops the
last two views, leaving the stack at view one. To finish, the code
performs a delayed animated push, adding view three behind view one,
creating the proper “back” button.
Although the main
view animation properly shows a push from view two to view three, be
aware that the navigation bar animation shows a push from root to Level
3. This should not be enough to get your application booted from the App
Store for violating human interaction guidelines but you might want to
use smart interface design to minimize visual discontinuities.
Recipe 1. Pushing Momentary Views
- (void) doPush: (id) nc { // With the stack back at view 1, push on view #depth+1 [nc pushViewController:[[TestBedViewController alloc] initWithDepth:depth+1] animated:YES]; }
- (void) push { if (depth < 2) { [self.navigationController pushViewController:[[TestBedViewController alloc] initWithDepth:depth+1] animated:YES]; return; }
// Push from current view to view #depth+1, showing the animation [self.navigationController pushViewController:[[TestBedViewController alloc] initWithDepth:depth+1] animated:YES];
// Get ready to push from view #1 to view #depth+1 [self performSelector:@selector(doPush:) withObject:self.navigationController afterDelay:0.05f];
// Pop off view #depth+1 and then view #depth [[self.navigationController topViewController] autorelease]; [self.navigationController popViewControllerAnimated:NO]; [[self.navigationController topViewController] autorelease]; [self.navigationController popViewControllerAnimated:NO];
}
|