shouldAutorotateToInterfaceOrientation not being called in iOS 6
Solution 1
PLEASE READ this CAREFULLY or you could loose 1-2 days of your life with going nuts and fighting, shaking, turning your test device like the chimp in the zoo which grabbed a visitor's mobile! Sooner or later...promise :)
IN iOS 6
shouldAutorotateToInterfaceOrientation:
is deprecated and replaced by
shouldAutorotate
it means 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;
}
BE AWARE
UIInterfaceOrientation
is a property of UIApplication
and only contains 4 possibilities which correspond to the orientation of the status bar:
UIInterfaceOrientationPortrait = UIDeviceOrientationPortrait,
UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight,
UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft
DO NOT CONFUSE IT WITH
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 you can theoretically use UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
which returns UIDeviceOrientation
- the device actual orientation - BUT you have to know that UIDeviceOrientation
is not always equal UIInterfaceOrientation
!!! For example, when your device is on a plain table you can receive unexpected value.
You can use UIInterfaceOrientation orientation = self.interfaceOrientation;
too which returns UIInterfaceOrientation
, the current orientation of the interface, BUT it's a property of UIViewController
, so you can access to this one only in UIViewController
classes.
If you'd like to support both prior iOS6 (iOS3/4/5) and iOS6 devices - which could be evident - just use both shouldAutorotateToInterfaceOrientation:
and shouldAutorotate
in your code.
From iOS 6 there are 3 levels and 3 steps which the device checks during app launch, which you have to control if you'd like.
1. Info.plist - Supported Interface Orientations
which you could set graphically in the Summary tab. The sequence of allowed orientations is IMPORTANT, which you can change manually by editing the info.plist
, and the device will choose the first when the app is launching! This is critical as the problem always the launch of the app when there is the chance that the [UIDevice currentDevice].orientation
is unknown, especially when we test our app on a flat surface.
BE AWARE There is two other settings possibility with (iPad) or (iPhone) extension, if you use any of them, it will use that setting of the current device or simulator and neglect the general settings without the extension. So if you run an iPhone only app and accidentally you left a "Supported Interface Orientations (iPad)" line somewhere in the plist even without any data, it will neglect the rules you have established earlier in the general settings (in my example for iPhone) and you could get a rejection for your App with a text "We found that your app did not meet the requirements for running on iPad..." even if your app doesn't intend to use a given orientation on iPhone, but iPad will use it which could cause unpredicted errors, as all iPhone apps have to run on iPad too during the submission process.
2. AppDelegate - application:supportedInterfaceOrientationsForWindow
returning a bit mask listing of every orientations you'd like to permit, which override the info.plist settings.This is called at least once every times the device rotates.
3. Top-level view controller or RootViewController - supportedInterfaceOrientations
which gives an intersection with the set of the app and app delegate, which has to have a non zero result to avoid crash. This is called at least once every times the device rotates, except there is an another method installed in our controller:
shouldAutorotate
which interferes with the app's permitted orientations, and gives a BOOL
with default YES
.
BE CAREFUL when you use `NavigationController`
as the topmost controller in your AppDelegate
, like this:
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 have to place the following code in your AppDelegate
as a category attachment to NavigationController
class, as this is the topmost controller, and if you haven't made a subcategory of it, you have no place/code where you can set its orientation settings, so you need to force it to check your real rootViewController
in this case the detailViewController
for the orientations:
@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 this you can set the preferred orientations in your "topmost" ViewController
(in my example this is the detailViewController
) with any of the methods you have available in iOS 6 for ViewControllers
, as below:
1. (BOOL)shouldAutorotate
2. (NSUInteger)supportedInterfaceOrientations
3. (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
Solution 2
Ok, I got it to work in iOS6 iPad Simulator. Yay. Here's what I did:
I just show you before and after, it should be self explanatory:
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;
}
As for the supported orientation, you can either specify in info.plist as such:
Or use code:
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait; // etc
}
Edit: On second thought, 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 (in sim anyways)
Solution 3
Setting the app window route controller rather than, just adding it's view as a subview worked for me (as Rocotilos did)
// [self.window addSubview:self.topLevelNavigationController.view];
self.window.rootViewController = self.topLevelNavigationController;
Solution 4
Here's a solution for iOS 5 and earlier code that doesn't involve duplicating your logic. Simply add this code to your view controller and it generates the supportedInterfaceOrientations from your existing shouldAutorotateToInterfaceOrientation 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;
}
Solution 5
A quick fix for me was to add this code on my root view controller
- (BOOL)shouldAutorotate {
return [self shouldAutorotateToInterfaceOrientation:self.interfaceOrientation];
}
This way I still use the same logic used for versions prior to iOS 6. Of course, I originally had set my rootViewController in my app delegates didFinishLaunchingWithOptions properly instead of just adding to the windows subviews.
Comments
-
Hesham almost 2 years
I'm using MGSplitViewController and I'm using
shouldAutorotateToInterfaceOrientation
to control the size of the master view controller on rotation.It's all working fine on iOS 5 but on iOS 6 (both simulator and iPad)
shouldAutorotateToInterfaceOrientation
is never called.Is this a bug that I should expect to be fixed with the final release of iOS 6 or something that I'm not aware of has changed?
-
strange over 11 yearsNope existing code does not work on iOS6. My app works on 5.x but not on iOS 6.
-
Carlos Moura over 11 yearsThese comments were useful for me: cocos2d-x.org/boards/6/topics/15447?r=15734
-
cheesus over 11 yearsThis does not work in iOS 6. Try the following: Create a new XCode project and choose the template
Single View Application
. The template'sAppDelegate
already contains the line you're suggesting. Then, overrideshouldAutorotateToInterfaceOrientation
in theViewController
, set a breakpoint and debug it. The breakpoint will never be hit (iOS 6). -
RK- over 11 yearsBut again this method is depreciated..Right?
-
jowie over 11 yearsNot sure about using
[[UIDevice currentDevice] orientation]
...UIDeviceOrientation
is not the same thing asUIInterfaceOrientation
. -
JugsteR over 11 yearsWell, shouldAutorotate is not deprecated, but shouldAutorotateToInterfaceOrientation is. However, that only means that the operating system doesn't call it any more. If you have implemented it, and it works you are free to call it. It is not deprecated for you. Of course, this is pertaining to changes in ios 6.
-
Veeru over 11 yearsThat was interesting and pointed me in the right direction. The interface issue was killing me, and my app even got rejected. My app's first version was for ios5 - no issues and approved in appstore. The second version i released with very minor changes was rejected because of orientation issues with ios6. Why does apple have to do this shit! Up-Vote for you :)
-
miho over 11 yearsUse || operators instead of magic numbers. This will make it much easier to read!
-
miho over 11 yearsThis is a nice idea. While I think it is not that hard, to just creating a implementation for the new method, in most situations, you still got an up-vote since this may be best solution when having a unique subclass of UIViewController which used as a base for all your controllers.
-
vampirewalk over 11 yearsIt seems that they are the same.
-
oddmeter over 11 yearsJust in case no one wants to read my post below, please also be aware that the device may not know it's orientation at the inception of app launch. As such, you may want to also check against
if (orientation == UIDeviceOrientationUnknown)
-
Jim Rhodes over 11 yearssupportedInterfaceOrientations is called for every view controller in my application, not just the root. shouldAutorotate never seems to get called for the root controller but does get called sometimes for the other controllers.
-
Xander Dunn over 11 yearssupportedInterfaceOrientations() is called on all of my UIViewControllers as well. Nevertheless, it seems to take the value of the root ViewController.
-
len over 11 yearsOr UIInterfaceOrientationMaskAllButUpsideDown.
-
Dejell over 11 yearsshouldAutorotateToInterfaceOrientation is deprecated in iOS6
-
DanSkeel about 11 yearsCheck out a bit more elegant solution
-
Sam B about 11 yearsThis is NOT the right answer. If you have specific logic built for lets say UIInterfaceOrientationPortraitUp then this code does nothing but walks through the whole direction and keeps calling shouldAutorotateToInterfaceOrientation over and over again
-
filou about 11 years@miho: NSInteger expects a number.
-
Joshua Dance almost 11 yearsDeprecated means that the function is no longer supported and might be removed in the future. If you want your apps to survive updates, don't use deprecated functions.
-
Jeff almost 11 yearsI believe supportedInterfaceOrientations:(UIWindow *)window should be supportedInterfaceOrientations.
-
Hossam Ghareeb almost 11 yearsshouldAutorotate is not deprecated. Really awesome solution, the only solution that worked with me
-
craigk almost 11 yearsin the last example what is the OrientationSettings_IOS6 in @implementation UINavigationController (OrientationSettings_IOS6)
-
BootMaker almost 11 years@craigk - It's a category definition, you can use any kind of name, it's arbitrary. With the usage of category you could attach methods to other classes especially if you couldn't reach or edit the .m file. Useful phenomenon check it in the literature.
-
entonio almost 10 yearsI'd personally have the older method call the new one rather than the reverse, but that's just me. People, the deprecation status of the old method should not matter when the implementations is your own.
-
Sergey Skoblikov over 9 yearsFrom the docs: interfaceOrientation: Convenience property that provides the current orientation of the interface, meaningful only if the view controller is taking up the full screen. Do not use this property for informing layout decisions. Instead, use the statusBarOrientation property.