Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement UIViewController rotation in response to orientation changes?

My app has about 10 different UIViewControllers, just one of which I want to switch to landscape mode if the device is rotated. (All the rest, I want to keep in portrait.)

In order to implement rotation on that one view, I needed to implement its controller's 'shouldAutorotate' method and return YES. Since this view is accessed via a navigation controller, I also needed to create a subclass of UINavigationController that implements 'shouldAutorotate' and return YES.

This solution works, but too well. I find that all of the UIViewControllers I push onto my subclass of UINavigationController respond to rotation, even if I implement 'shouldAutorotate' and return NO. (Remember: I only want one particular UIViewController to respond to rotation, not every one in the navigation controller's stack.)

So, my question is: how do I best do this? All the solutions I can come up with seem 1) cumbersome, and 2) worse, don't seem to work.

Thanks very much.

like image 622
Greg Maletic Avatar asked May 14 '10 23:05

Greg Maletic


2 Answers

when you implement UINavigationController, this class is your the parent that controls all the children viewControllers that will be pushed into the stack. Therefore, the RootViewController is the only controller that say Yes or No to autorotation. Even if, you are passing Yes to auto-rotation in children view controllers, they don't count!

This is the nature of UINavigationController. So to change it, you have two choices:

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

2- Change your design so that it is more compatible to UINavigationController. That single view that should rotate, should be get called by the RootViewController (not the Navigation Root View Controller -- they are named the same, but are totally different), the view that hosts NavController. And when the device rotates, it will either push the NavController to the view or the other.

3- The other method, which will also work, but is not recommended because it violates the concept of MVC, is that your NavController can listen to Notifications. That particular child view that CAN and SHOULD rotate can cast a notification -- e.g. rotateMe, and once the NavController hears it, it rotates.

As I said, it will work, but it violates the MVC model -- which is fine to Apple, but from programming perspective is not recommended.

If you need further explanation about either of them, please let me know.

like image 175
Canopus Avatar answered Sep 27 '22 17:09

Canopus


I do this by having a root view controller (this could be a UITabBarController) and in it's 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 happened, and what orientation the phone is in:

- (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) {






}

}

Within that didRotate: you can look at which is the visible viewController and do what you want from there.

I present a modal view controller in landscape mode when a particular view controller is visible and the phone is rotated into landscape. If any other view controller is visible, i ignore the event.

I force my modal view controller to display in landscape mode in its viewWillAppear method - i can give anyone this code if they want it.

Hope this helps.

Dave

like image 37
bandejapaisa Avatar answered Sep 27 '22 17:09

bandejapaisa