ShouldAutorotateToInterfaceOrientation not called in iOS 6

I use MGSplitViewController, and I use shouldAutorotateToInterfaceOrientation to control the size of the main view controller during rotation.

Everything works fine on iOS 5, but on iOS 6 (both simulator and iPad) shouldAutorotateToInterfaceOrientation never called.

Is this a bug that I should expect to fix with the final version of iOS 6, or has something I don’t know about changed?

+56
ios ios6 orientation
Sep 04
source share
17 answers

PLEASE READ THIS ATTENTIVELY, or you can lose 1-2 days of your life by losing your mind and fighting, shaking, turning your test device like a chimpanzee into a zoo that grabbed a visitor's mobile! Sooner or later ... promise :)

IN iOS 6

 shouldAutorotateToInterfaceOrientation: 

deprecated and replaced by

 shouldAutorotate 

this means that iOS 6 will never call shouldAutorotateToInterfaceOrientation :

so if you used the following in your application

BEFORE iOS6 (iOS5, iOS4, etc.)

 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { if (interfaceOrientation == UIInterfaceOrientationPortrait) { // your code for portrait mode } return YES; } 

you should use

AFTER iOS 6+

 - (BOOL)shouldAutorotate { UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; if (orientation == UIInterfaceOrientationPortrait) { // your code for portrait mode } return YES; } 

FAMILIARIZE

UIInterfaceOrientation is a property of UIApplication and contains only 4 features that correspond to the orientation of the status bar:

 UIInterfaceOrientationPortrait = UIDeviceOrientationPortrait, UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown, UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight, UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft 

DO NOT SAVE

UIDeviceOrientation , which is a property of the UIDevice class and contains 7 possible values:

 UIDeviceOrientationUnknown - Can not be determined UIDeviceOrientationPortrait - Home button facing down UIDeviceOrientationPortraitUpsideDown - Home button facing up UIDeviceOrientationLandscapeLeft - Home button facing right UIDeviceOrientationLandscapeRight - Home button facing left UIDeviceOrientationFaceUp - Device is flat, with screen facing up UIDeviceOrientationFaceDown - Device is flat, with screen facing down 

even theoretically, you can use the UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; that returns a UIDeviceOrientation - the actual orientation of the device - BUT you should know that UIDeviceOrientation not always equal to UIInterfaceOrientation !!! For example, when your device is on a simple table, you may get an unexpected value.

You can use UIInterfaceOrientation orientation = self.interfaceOrientation; which returns the UIInterfaceOrientation , the current orientation of the interface, BUT this is a property of the UIViewController , so you can only access this in the UIViewController classes.

If you want to support both previous iOS6 devices (iOS3 / 4/5) and iOS6, which may be obvious, just use both shouldAutorotateToInterfaceOrientation: and shouldAutorotate in your code.

From iOS 6, there are 3 levels and 3 steps that the device checks during the launch of the application, which you must control if you want.

 1. Info.plist - Supported Interface Orientations 

which you can set graphically on the Summary tab. The sequence of permitted orientations is IMPORTANT, which you can change manually by editing info.plist , and the device will select the first one when the application starts! This is very important because the problem always lies in launching the application when it is likely that [UIDevice currentDevice].orientation unknown, especially when we test our application on a flat surface.

plist setting in XCode (Info)

LIMIT There are two more settings with the extension (iPad) or (iPhone), if you use any of them, it will use this setting of the current device or simulator and neglect the general settings without extension. Therefore, if you run the iPhone application only for iPhone, and by chance you leave the line “Supported Interfaces (iPad)” somewhere in the plist even without any data, it will neglect the rules that you set earlier in the general settings (in my example for iPhone), and you may receive a rejection of your application with the text "We found that your application does not meet the requirements for working on the iPad ..." even if your application does not intend to use this orientation on the iPhone, but the iPad use it, which can lead to failure apparent errors, since all iPhone apps must run on the iPad too during the upload process.

 2. AppDelegate - application:supportedInterfaceOrientationsForWindow 

returns a list of mini masks of all permissions that you want to allow, which override info.plist parameters. This is called at least once every time the device rotates.

 3. Top-level view controller or RootViewController - supportedInterfaceOrientations 

which gives the intersection with the delegate set of the application and the application, which must have a nonzero result to avoid a failure. This is called at least once every time the device rotates, except that a different method is installed in our controller:

 shouldAutorotate 

which prevents the application from resolving, and gives BOOL by default YES .

 BE CAREFUL when you use `NavigationController` 

as the topmost controller in your AppDelegate , for example:

 DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:nil]; UINavigationController *navigationController=[[UINavigationController alloc] initWithRootViewController:detailViewController]; self.window.rootViewController =nil; self.window.rootViewController = navigationController; [self.window makeKeyAndVisible]; return YES; 

in this case, you should put the following code in your AppDelegate as a category attachment in the NavigationController class, since this is the topmost controller, and if you did not subcategory it, you do not have a place / code where you can set your orientation settings, so you you need to make it check your real rootViewController in this case the detailViewController for orientation:

 @implementation UINavigationController (OrientationSettings_IOS6) -(BOOL)shouldAutorotate { return [[self.viewControllers lastObject] shouldAutorotate]; } -(NSUInteger)supportedInterfaceOrientations { return [[self.viewControllers lastObject] supportedInterfaceOrientations]; } - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation]; } @end 

after that, you can set your preferred orientations in your "top" ViewController (in my example, it is a detailViewController ) with any of the methods available in iOS 6 for ViewControllers , as shown below:

 1. (BOOL)shouldAutorotate 2. (NSUInteger)supportedInterfaceOrientations 3. (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation 
+113
Feb 18 '13 at 14:20
source share

Ok, I got it to work in iOS6 iPad Simulator. Hurrah. Here is what I did:

I just show you before and after, it should be clear:

before

 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { if (interfaceOrientation==UIInterfaceOrientationPortrait) { // do some sh!t } return YES; } 

after

 - (BOOL)shouldAutorotate { UIInterfaceOrientation orientation = [[UIDevice currentDevice] orientation]; if (orientation==UIInterfaceOrientationPortrait) { // do some sh!t } return YES; } 

Regarding the supported orientation, you can specify in info.plist as such: Supported Orientation pic

Or use the code:

 -(NSUInteger)supportedInterfaceOrientations{ return UIInterfaceOrientationMaskPortrait; // etc } 



Edit: if you think about it, if you plan to support lower versions (iOS4.3 / 5 / 5.1), as well as 6.0, then just include both methods with the same code content. Works for me (anyway in sim).

+54
Sep 17 '12 at 8:20
source share

Setting up the route controller of the application window, and not just adding it as a preview for me (as Rokotilos did)

 // [self.window addSubview:self.topLevelNavigationController.view]; self.window.rootViewController = self.topLevelNavigationController; 
+20
Sep 21 '12 at 9:35
source share

Here is a solution for iOS 5 and earlier code that does not include duplicating your logic. Just add this code to your view controller and it will generate supported interface elements from the existing toAutorotateToInterfaceOrientation method.

 -(BOOL)shouldAutorotate{ return YES; } -(NSInteger)supportedInterfaceOrientations{ NSInteger mask = 0; if ([self shouldAutorotateToInterfaceOrientation: UIInterfaceOrientationLandscapeRight]) mask |= UIInterfaceOrientationMaskLandscapeRight; if ([self shouldAutorotateToInterfaceOrientation: UIInterfaceOrientationLandscapeLeft]) mask |= UIInterfaceOrientationMaskLandscapeLeft; if ([self shouldAutorotateToInterfaceOrientation: UIInterfaceOrientationPortrait]) mask |= UIInterfaceOrientationMaskPortrait; if ([self shouldAutorotateToInterfaceOrientation: UIInterfaceOrientationPortraitUpsideDown]) mask |= UIInterfaceOrientationMaskPortraitUpsideDown; return mask; } 
+17
Oct 16 '12 at 20:05
source share

The quick fix for me was to add this code to my root view controller

 - (BOOL)shouldAutorotate { return [self shouldAutorotateToInterfaceOrientation:self.interfaceOrientation]; } 

Thus, I still use the same logic that was used for versions prior to iOS 6. Of course, I initially set my rootViewController in my delegates to the didFinishLaunchingWithOptions app correctly, rather than just adding subviews to the windows.

+15
Sep 25
source share

And while a series of answers indicate a solution - that for the implementation of shouldAutorotate and supportedInterfaceOrientations for building iOS 6, you should also know that if your view controller is located in the navigation controller, then none of them will be because the runtime will call them in the instance UINavigationController and otherwise ignores your code.

Apparently, the “solution” refers to a subclass of UINavigationController and implements these new methods in this subclass, as described here: iOS 6 UITabBarController supports orientation with the current UINavigation controller

And then you have the pleasure of changing all your code where you use the UINavigationController to use this new subclass.

This should be one of the most pointless and annoying changes to the iOS release I've ever seen.

+11
Oct. 11
source share

Ios 5

 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{ if (UIInterfaceOrientationLandscapeLeft) { return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft); } if (UIInterfaceOrientationLandscapeRight) { return (interfaceOrientation == UIInterfaceOrientationLandscapeRight); } return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft); } 

Ios 6

 -(BOOL)shouldAutorotate{ return YES; } -(NSInteger)supportedInterfaceOrientations:(UIWindow *)window{ // UIInterfaceOrientationMaskLandscape; // 24 // // UIInterfaceOrientationMaskLandscapeLeft; // 16 // // UIInterfaceOrientationMaskLandscapeRight; // 8 // // UIInterfaceOrientationMaskPortrait; // 2 // return UIInterfaceOrientationMaskLandscape; return 24; } 
+9
Oct 10
source share

This worked for me with iOS6 and Xcode 4.5 GM:

In AppDelegate.m

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ..... // self.window.rootViewController = self.navigationController; [window setRootViewController:navigationController]; ..... return YES; } 

on ViewController:

 - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration { if (UIInterfaceOrientationIsLandscape(interfaceOrientation)) { // landscape } else { //portrait } } 
+3
Sep 14
source share

In response to @Rocotilos, I have an add-on that happened in my code that I have not seen in other forums. I came across a situation where at the very beginning of the application life cycle, where the orientation was not known in the shouldAutorotate method. This caused the application to not display the view in the landscape. After several turns in the simulator, it worked fine.

My scenario is that there are certain types that appear when we want a landscape layout. Thus, we would not want theAutorotate to return YES. I understand that this may be a rare case for some, but I spent a lot of time diagnosing this and wanted to get through. Hope this will be helpful.

 - (BOOL) shouldAutorotate { BOOL shouldRotate = NO; UIInterfaceOrientation orientation = [[UIDevice currentDevice] orientation]; if ([self IsCaseWhereWeDontWantLandscapeAutorotation]) { shouldRotate = NO; } else if (orientation == UIDeviceOrientationUnknown) { //Handle the case where the device orientation is not yet known shouldRotate = YES; } else { //Handle the normal case shouldRotate = (orientation == UIInterfaceOrientationMaskLandscape); } return shouldRotate; } 
+3
Nov 26 '12 at 2:00
source share

It turns out that the handlers of these calls are processed only by the root representation. In my case, it was a regular UINavigationController. I had to change this to a subclass file where I added methods.

In my case, I only need a portrait of the root view, and the rest is portrait + landscape.

Appdelegate.h

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; // Override point for customization after application launch. S2MBookAppRootViewController *masterViewController = [[[S2MBookAppRootViewController alloc] initWithNibName:pref.rootNibName bundle:nil] autorelease]; self.navigationController = [[[S2MBookAppNavController alloc] initWithRootViewController:masterViewController] autorelease]; self.window.rootViewController = self.navigationController; [self.window makeKeyAndVisible]; [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque animated:YES]; return YES; } 

And S2MBookAppNavController (subclass of UINavigationController)

 - (BOOL)shouldAutorotate { return YES; } - (NSUInteger)supportedInterfaceOrientations { if([self.viewControllers count] == 1) return UIInterfaceOrientationMaskPortrait; return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscape; } 

UPDATE: If you want to force the orientation (when you click a new view on the navigation controller), try this.

Make your UINavigationController also your own delegate:

 @interface S2MBookAppNavController : UINavigationController <UINavigationControllerDelegate> @end 

And in the .m file

 - (void)viewDidLoad { [super viewDidLoad]; self.delegate = self; // Do any additional setup after loading the view. } - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated { if ([UIViewController respondsToSelector:@selector(attemptRotationToDeviceOrientation)]) { //present/dismiss viewcontroller in order to activate rotating. UIViewController *mVC = [[[UIViewController alloc] init] autorelease]; [self presentModalViewController:mVC animated:NO]; [self dismissModalViewControllerAnimated:NO]; } } 
+2
Oct 23
source share

Yes, the problem is only calling the window.rootViewController method to return the orientation mask. Therefore, the supportedInterfaceOrientations method must be implemented in the viewController, which is set as window.rootViewController. But in most cases this object is not an ordinary class, for example. UINavigationController. One possible solution is to subclass UINavigationController. But Apple says, “This class is not intended to be a subclass,” so I preferred to use another UIViewController to handle the orientation, and added the UINavigationController as a child.

 MyRootViewController * myRoot = [MyRootViewController new]; self.window.rootViewController = myRoot; [myRoot addChildViewController:navigationController]; [myRoot.view addSubview:navigationController.view]; 

and in the implementation methods of MyRootViewController:

 - (BOOL)shouldAutorotate { return YES; } - (NSUInteger)supportedInterfaceOrientations { // return your mask here eg: return UIInterfaceOrientationMaskPortrait; } 
+2
Oct 30 '12 at 11:25
source share

Here's a quote from the Apple iOS SDK, XCode4.5 + (see UIViewController Class Reference, Handling Viewing Turns):

In iOS 6, your application supports the interface orientation defined in your application Info.plist file. The view controller can override the supportedInterfaceOrientations method to limit the list of supported orientations. Typically, the system calls this method only on the window root view controller or the view controller presented to fill the entire screen; child view controllers use the portion of the window provided for them by their parent view controller and no longer directly participate in decisions about which rotations are supported.

Also in iOS6, the shouldAutorotateToInterfaceOrientation: method of the UIViewController class is already deprecated.

So, in the root view controller, you do ff:

 - (BOOL)shouldAutorotate { return YES; } - (NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskPortrait; } 

Btw, the “root view controller” is any subclass of the UIViewController that you set as the rootViewController of your appDelegate object . You usually do this in the appDelegate : application didFinishLaunchingWithOptions : method .

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. self.window.rootViewController = [FFDashboardController create]; [self.window makeKeyAndVisible]; return YES; } 

Regarding the use of the UINavigationController as the root VC, exit Vladimir answer .

+2
Nov 15
source share

The notes under the UIKit heading here: http://developer.apple.com/library/ios/#releasenotes/General/RN-iOSSDK-6_0/_index.html%23//apple_ref/doc/uid/TP40012166-CH1-SW19 give some clues for an answer, but this is not the whole picture. I do not have a complete picture yet, but here is what I have found so far for RTM for iOS 6.0.

If you are not really restricting the supported orientations and instead want to do something because the user has rotated the device, then you can move the logic to

 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 

to

 - (void)viewWillLayoutSubviews 

instead.

It may be a direct replacement, but I have not tested the iOS version below.

If you want to limit the supported orientations, you must do this at the UIApplicationDelegate level with

 -(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window 

The documentation states that "The system determines whether orientation is maintained by intersecting the value returned by the supportedInterfaceOrientationsForWindow: method with the value returned by the supportedInterfaceOrientations method of the top-most full-screen controller." but in experiments, I found that the system ignores the supported my view controllers

 -(NSUInteger)supportedInterfaceOrientations 

although the method is being called.

+1
Oct 03
source share

I have a number of view controllers in a UINavigationController, one of which was supposed to be just a landscape. I fixed it by subclassing the UINavigationController and adding the following code:

 - (NSUInteger)supportedInterfaceOrientations{ return [[self.viewControllers lastObject] supportedInterfaceOrientations]; } 

This ensures that the top controller will determine the orientation.

However, there is a reptile: if you switch from vc, which is limited to the landscape, which supports any orientation, the new view will be displayed in the landscape, regardless of the orientation of the phone. To combat this, I put the following code in an unlimited number of views:

 - (NSUInteger)supportedInterfaceOrientations{ if(UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation])) return UIInterfaceOrientationMaskPortrait; else return UIInterfaceOrientationMaskLandscape; } 
+1
Jan 23 '13 at 12:45
source share
 -(BOOL)shouldAutorotate { UIDeviceOrientation orientation = [UIDevice currentDevice].orientation; if (orientation == UIDeviceOrientationUnknown) { return YES; } return [self shouldAutorotateToInterfaceOrientation:self.interfaceOrientation]; } 
+1
May 10 '13 at 5:49
source share

Apple uses the obsolete toautorate method from ios6, using these methods instead. See your xcode docs

 - (BOOL)shouldAutorotate NS_AVAILABLE_IOS(6_0); - (NSUInteger)supportedInterfaceOrientations NS_AVAILABLE_IOS(6_0); // Returns interface orientation masks. - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation NS_AVAILABLE_IOS(6_0); 
0
Nov 13 '12 at 13:30
source share

His work for me:

 - (BOOL)shouldAutorotate { return YES; } - (NSUInteger)supportedInterfaceOrientations { NSUInteger orientations = UIInterfaceOrientationMaskPortrait; if ([self isKindOfClass:[YourViewController class]]) { // Your view class orientations |= UIInterfaceOrientationMaskPortraitUpsideDown; } return orientations; } 

orientation:

 orientations |= UIInterfaceOrientationMaskLandscapeLeft; orientations |= UIInterfaceOrientationMaskLandscapeRight; 
0
Mar 08 '13 at 10:35
source share



All Articles