I am building an app that uses multiple types of screens--all which warrant their own custom view controllers. I am successfully switching between view controllers and their related views by reassigning the main window
's rootViewController
with a method in my app delegate like the following:
- (void)changeRootViewController:(NSString *)controllerName
{
if (controllerName == @"book") {
rootViewController = (UIViewController *)[[BookViewController alloc] init];
[self.window setRootViewController:rootViewController];
} else if (controllerName == @"something_else") {
// Use a different VC as roowViewController
}
}
The way that I am doing this seems like it just can't be best practice, however. I don't want to use a UINavigationController
or a UITabBarController
as the rootViewController
, either. Is this the wrong way to be doing this, and if so, how should I be approaching this differently?
I thought this would have been covered somewhere, but (I feel as if) I've Googled the heck out of it, looked for related questions, etc. Sorry if I've missed something!
One great way to do this is by using iOS5+'s UIViewController's ability to have child UIViewControllers (it's called view controller containment). I certainly had a difficult time figuring out how to do this until I watched the WWDC video that explains this in good detail.
In a nutshell, it allows you to create your own parent view controller that owns a series of child view controllers. This single parent view controller can (and probably should, unless you're doing some really fancy stuff :P) sit as your app's window's root view controller. This method of having a single view controller act as a parent (and facilitate the adding, removing, and transitioning of the child view controllers) is reminiscent of what UINavigationController does (which is Apple's intent). Now you can create your own UINavigationController-like parent view controller, but have totally different transition animations and UI.
As an example, in the parent view controller, in the viewDidLoad, I add the first child controller like this:
self.currentlyDisplayedChildViewController = [[TheFirstViewController alloc] init];
[self addChildViewController:self.currentlyDisplayedChildViewController];
[self.view addSubview:self.currentlyDisplayedChildViewController.view];
[self.currentlyDisplayedChildViewController didMoveToParentViewController:self];
Then I would have a function to do the transition to the next child view controller (NOTE: this function belongs in the parent view controller -- the view controller that's going to act as your UINavigationController):
- (void)transitionToViewController:(UIViewController *)nextChildViewController
{
[self addChildViewController:nextChildViewController];
__weak TheParentViewController *me = self;
[self transitionFromViewController:self.currentlyDisplayedChildViewController
toViewController:nextChildViewController
duration:1.0f
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:nil
completion:^(BOOL finished)
{
[nextChildViewController didMoveToParentViewController:self];
[me.currentlyDisplayedChildViewController willMoveToParentViewController:nil];
[me.currentlyDisplayedChildViewController removeFromParentViewController];
me.currentlyDisplayedChildViewController = nextChildViewController;
}];
}
One thing really nice is you can use all the standard UIViewAnimationTransition options (or define your own custom animation in the animations block. Additionally, any orientation rotations events are automatically forwarded from the parent view controller to the child view controllers. This was one of that hairiest problems with doing custom root view controller manipulations on your own.
I would suggest taking a look at WWDC2011 video titled "Implementing UIViewController Containment".