Transitioning to landscape rotation within a uinavigationcontroller
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)
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];
}
Implement the following method, which should be called when the view is pushed onto the navigation stack:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return UIInterfaceOrientationIsLandscape(interfaceOrientation);
}
This should automatically rotate everything sideways as soon as you push it on to the stack, since the view does not support portrait orientations.
If I'm wrong and it doesn't, you can always force horizontal orientation by setting the status bar orientation:
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:animated];
}
This is my solution, based on Ed Marty on this page and Simon here - http://simonwoodside.com/weblog/2009/2/27/iphone_programming_how_to_switch/
Within the preceding view, call this from your button or table cell selected method
- (void) launchLandscape
{
LandscapeViewController *controller = [[LandscapeViewController alloc] initWithNibName:@"LandscapeViewControllerView" bundle:nil];
[self.navigationController setNavigationBarHidden:YES];
controller.hidesBottomBarWhenPushed = YES;
[[self navigationController] pushViewController:controller animated:NO];
[controller release];
}
And then within the landscape view
- (void)viewWillAppear:(BOOL)animated {
[[UIApplication sharedApplication] setStatusBarHidden:YES animated:NO];
[UIApplication sharedApplication].statusBarOrientation = UIInterfaceOrientationLandscapeRight;
CGAffineTransform landscapeTransform = CGAffineTransformMakeRotation( degreesToRadian(90) );
landscapeTransform = CGAffineTransformTranslate( landscapeTransform, +90.0, +90.0 );
[self.view setTransform:landscapeTransform];
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:NO];
}
-(IBAction)backButton:(id)sender
{
[UIApplication sharedApplication].statusBarOrientation = UIInterfaceOrientationPortrait;
[[UIApplication sharedApplication] setStatusBarHidden:NO animated:NO];
[self.navigationController setNavigationBarHidden:NO];
[self.navigationController popViewControllerAnimated:NO];
}
It's a bit 'sudden'. You can't really put animation on any of it because it looks too glitchy. I guess it could be improved by pushing a intermediate view with animation (a plain black view) and then automatically doing the above stuff to go to the final landscape.
精彩评论