Monday, November 26, 2012

iOS6, Rotation.

Hi, it's been a while since I posted some thing.

Ok, This post is to fix the auto-rotation problem that has been around since the release of iOS6.

To be clear, the problem is that iOS6 doesn't support - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; any more. And hence, our apps/code won't behave as expected any more.

In this post, I'll be using three methods/callbacks were introduced in iOS6 which are (BOOL)shouldAutorotate- (NSUInteger)supportedInterfaceOrientations and (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window.

One important thing to know, (BOOL)shouldAutorotate and (NSUInteger)supportedInterfaceOrientations are added to the topmost parent of the view controller that you want to control its rotation. if, of-course, the view controller is a root view controller, then these methods will be added to it directly.

I hate to repeat myself, but for the sake of clarification, if your root-view-controller is a navigation-controller and you want to control the rotation of a view-controller inside the navigation-controller then  (BOOL)shouldAutorotate and (NSUInteger)supportedInterfaceOrientations will be added to the navigation-controller NOT the view-controller itself.

If you have a tab-bar-controller that contains a navigation-controller inside which lies the view-controller that you want to control its rotation, then (BOOL)shouldAutorotate and (NSUInteger)supportedInterfaceOrientations will be added to the topmost parent which is - in this case - the tab-bar-controller.

How to add those methods to a tab-bar-controller or a navigation-controller?
  1. By subclassing them and overriding the methods inside them.
  2. By adding them to a category of your tab-bar-controller's or navigation-controller's type. I like this method because, it's simpler specially if the code is already written and i'm doing some slight modifications.
Now, lets take the case of a tab-bar-controller that contains a navigation-controller inside which lies the view-controller that you want to control its rotation as an example. you'll do as follows:
  1. add (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window to your appdelegate as follows:
     - (NSUInteger)application:(UIApplication *)application 
    supportedInterfaceOrientationsForWindow:(UIWindow *)window {  
       return (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft |  
           UIInterfaceOrientationMaskLandscapeRight);  
     }  
    

  2. create a category inside your appdelegate as follows:
     @implementation tab-view-controller (fixingRotation)  
       
     - (BOOL)shouldAutorotate {  
        
       if ([((UINavigationController *)[[((AppDelegate *)[[UIApplication sharedApplication]
     delegate]).tabBarController viewControllers] objectAtIndex:self.selectedIndex])
    .visibleViewController isKindOfClass:[myViewController class]]) {  
           
         return YES;  
       }  
       else{  
           
         return NO;  
       }  
     }  
     -(NSUInteger) supportedInterfaceOrientations {  
       return (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft |  
           UIInterfaceOrientationMaskLandscapeRight);  
     }  
       
     @end  
And your done.

Don't remove -(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation from your code to keep supporting iOS5.

It's recommended to see the documentation for better understanding of the callbacks.

That's it, don't hesitate to comment, to share your knowledge and to correct me.