How to implement rotation of a UIViewController in response to orientation changes?

My application has about 10 different UIViewControllers, only one of which I want to switch to landscape mode if the device is rotated. (Everything else, I want to keep the portrait.)

To implement the rotation on this one view, I needed to implement its controller "shouldAutorotate" method and return YES. Since this view is accessible through the navigation controller, I also need to create a subclass of UINavigationController that implements "shouldAutorotate" and returns YES.

This solution works, but too well. I believe that all the UIViewControllers that I click on my subclass of UINavigationController respond to rotation, even if I implement "shouldAutorotate" and return NO. (Remember: I want one particular UIViewController to respond to a rotation, and not everyone on the navigation controller stack.)

So my question is: how do I best do this? All the solutions that I can come up with seem 1) cumbersome, and 2) worse, it seems, do not work.

Many thanks.

+7
iphone uiviewcontroller screen-orientation
source share
4 answers

when you implement the UINavigationController, this class is your parent that controls all the child viewControllers that will be pushed onto the stack. Thus, RootViewController is the only controller that says β€œYes” or β€œNo” autorotation. Even if you pass Yes for automatic rotation in the child view controllers, they do not count!

This is the character of the UINavigationController. To change it, you have two options:

1- Manually manipulate it, which requires you to go through bulky codes.

2 Modify the design to be more compatible with the UINavigationController. This is the only view that needs to rotate, it must be called by the RootViewController (and not the root navigation controller - they are called the same, but completely different), the view in which the NavController is located. And when the device rotates, it either clicks the NavController on the view, or another.

3 Another method, which will also work, but is not recommended, since it violates the concept of MVC, is that your NavController can listen to notifications. This particular kind of child, which MAY and SHOULD rotate, may file a notification - for example. rotateMe, and as soon as the NavController hears it, it rotates.

As I said, it will work, but it violates the MVC model - this is good for Apple, but not recommended from a programming point of view.

If you need further explanation on any of them, please let me know.

+2
source share

I do this with a root view controller (it could be a UITabBarController), and in it the viewDidLoad method, I subscribe to rotation events:

[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(didRotate:) name:@"UIDeviceOrientationDidChangeNotification" object:nil]; 

Then, in the didRotate method: I look at which view controller is visible when the rotation occurred, and in what orientation the phone is:

 - (void) didRotate:(NSNotification *)notification { UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; /* DEVICE JUST ROTATED TO PORTRAIT MODE orientation == UIDeviceOrientationFaceUp || orientation == UIDeviceOrientationFaceDown */ if(orientation == UIDeviceOrientationPortrait) { /* DEVICE JUST ROTATED TO LANDSCAPE MODE */ }else if(orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight) { } } 

Inside this didRotate: you can see which one is the visible viewController, and do what is required of you.

I present a modal view controller in landscape mode when a specific view controller is displayed and the phone rotates into landscape. If any other view controller is visible, I ignore the event.

I make my modal view controller display in landscape mode in my viewWillAppear method - I can give this code to someone if he wants to.

Hope this helps.

Dave

+1
source share

Returns YES in a subclass of the navigation controller only if [[navController topViewController] isKindOfClass: [RotatingViewController class]]

+1
source share

I saw examples using how you do this, but couldn't make it work correctly. I found a better way to do this from the Apple examples. You basically implement presentModalViewController and create another view. UIKit performs a basic rotation animation and disappears between views. You must implement the rotated view as a delegate class so that it can call it back to the calling class in order to reject it and update the orientation.

 - (void)orientationChanged:(NSNotification *)notification { // We must add a delay here, otherwise we'll swap in the new view // too quickly and we'll get an animation glitch NSLog(@"orientationChanged"); [self performSelector:@selector(updateLandscapeView) withObject:nil afterDelay:0]; } 

And then, to display the terrain screen:

 - (void)updateLandscapeView { PortraitView *portraitView = [[PortraitView alloc] init]; portraitView.delegate = self; UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation; if (UIDeviceOrientationIsLandscape(deviceOrientation) && !isShowingLandscapeView) { [self presentModalViewController: portraitView animated:YES]; isShowingLandscapeView = YES; } else if (deviceOrientation == UIDeviceOrientationPortrait && isShowingLandscapeView) { [self dismissModalViewControllerAnimated:YES]; isShowingLandscapeView = NO; } [portraitView release]; } 
0
source share

All Articles