Objective-c – Transitioning to landscape rotation within a uinavigationcontroller

cocoa-touchiphoneobjective cuinavigationcontroller

I want to push a landscape view from within a uinaviagtioncontroller, whose initial view is in portrait…
So you click a button, or tableviewcell, and the screen rotates 90° into the new view..

How would I manage that? This is similar to how the Youtube app works when transitioning from movie info screen to the actual movie.

(note: i am not interested in what rotation the user is holding the device)

Best Answer

What appears in YouTube app when transitioning from the movie info screen to the actual movie is not navigation interface - it's a modal view. This always works reliably: if you show a view modally (using presentModalViewController) and it can appear in only one orientation, the app rotates to that orientation.

So, the solution is, don't push your landscape view into the navigation controller; present it as a modal view.

Okay, but perhaps you want to fool the user into believing that we are still in the navigation interface? Then give the modal view a navigation interface configured to look like the main navigation interface! So when you present the modal view, it will appear to the user as if the navigation interface has rotated (though there will not be a rotation animation).

Now, the only problem is that the navigation interface in the modal view has no Back button if we are looking at its root view. This breaks the illusion (and makes it hard for the user to come back). The solution to that is a trick: push the landscape view twice into the navigation interface before presenting it as a modal view. That way, what is showing in the navigation interface is the second view on the stack, and so there is a Back button. Then, in the navigation controller delegate, catch the Back button and dismiss the modal view when the user tries to return to what you know to be the root level. So:

- (void) doButton: (id) sender { // appear to navigate into a landscape view
    SecondViewController* sec = [[SecondViewController alloc] init];
    sec.title = self.title; // to give the correct Back button title
    UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:sec];
    SecondViewController* sec2 = [[SecondViewController alloc] init];
    [nav pushViewController:sec2 animated:NO];
    [self presentModalViewController:nav animated:YES];
    nav.delegate = self; // so that we know when the user navigates back
}

// and here's the delegate method
- (void)navigationController:(UINavigationController *)navigationController 
      willShowViewController:(UIViewController *)viewController 
                    animated:(BOOL)animated {
    if (viewController == [navigationController.viewControllers objectAtIndex:0])
        [self dismissModalViewControllerAnimated:YES];
}