iOS - UISupportedInterfaceOrientations and shouldAutorotateToInterfaceOrientation - ios

I am looking for some clarification on how to allow only certain orientations for your iOS app. I am aware of UISupportedInterfaceOrientations and shouldAutorotateToInterfaceOrientation but I am a little confused on their uses and exactly how they fit together.
I attempted to use UISupportedInterfaceOrientations to only allow landscape orientations, which appeared to have no affect until I researched in to it and read that it affects the initial orientation. Upon testing this, my app does appear to only open in landscape but quickly rotates if the screen is portrait.
I know you can use shouldAutorotateToInterfaceOrientation to limit the allowed orientations, for example:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft) ||
(interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
However, while doing some reading online I read shouldAutorotateToInterfaceOrientation is deprecated as of iOS6.
Basically my questions are:
What is the correct approach for limiting screen orientations across
multiple versions of iOS?
Is the only use of UISupportedInterfaceOrientations to limit the
initial orientation?
Edit:
To expand on the accepted answer, shouldAutorotate works in iOS6. As a quick fix if you've already implemented your logic in shouldAutorotateToInterfaceOrientation and/or you want to support earlier versions of iOS, you can do the following:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft) ||
(interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
- (BOOL)shouldAutorotate {
return [self shouldAutorotateToInterfaceOrientation:self.interfaceOrientation];
}

The method you need to use for rotation instead of shouldAutorotateToInterfaceOrientation is just shouldAutorotate
Handling rotation, according to the AppleDoc for ViewControllers:
In iOS 6, your app supports the interface orientations defined in your app’s Info.plist file. A view controller can override the supportedInterfaceOrientations method to limit the list of supported orientations. Generally, the system calls this method only on the root view controller of the window or a 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 participate in directly in decisions about what rotations are supported. The intersection of the app’s orientation mask and the view controller’s orientation mask is used to determine which orientations a view controller can be rotated into.
You can override the preferredInterfaceOrientationForPresentation for a view controller that is intended to be presented full screen in a specific orientation.
The method shouldAutorotateToInterfaceOrientation is deprecated, as are some methods for handling responses to device rotation.
For supporting methods of multiple versions of iOS, Here's something else that Apple has said:
For compatibility, view controllers that still implement the shouldAutorotateToInterfaceOrientation: method do not get the new autorotation behaviors. (In other words, they do not fall back to using the app, app delegate, or Info.plist file to determine the supported orientations.) Instead, the shouldAutorotateToInterfaceOrientation: method is used to synthesize the information that would be returned by the supportedInterfaceOrientations method.
Taken from release notes

To answer your second question:
Yes, the "UISupportedInterfaceOrientations" entry in the Info.plist is used only for initial startup of your app, making sure it doesn't start your app in an orientation it doesn't support, so that it's not required to perform a rotation right away.
Also, overriding "application:supportedInterfaceOrientationsForWindow" in your AppDelegate is pretty useful if your app never wants to use particular orientations (e.g. for a game that only does landscape).
Lastly, and this is a common error, on iPhone and iPod Touch devices, the device should never rotate to UIInterfaceOrientationPortraitUpsideDown! That's because these devices (contrary to an iPad) do not let the user lock a device in landscape mode with the Lock soft button - that button only locks into portrait. Therefore, if a user, laying on his side, wants to use an app in landscape mode, he cannot do this if your app goes into the upside down orientation. But if you disallow that rotation, then it works.

Related

iOS 9 supportedInterfaceOrientations not working

I have a UIViewController with the following code:
- (BOOL) shouldAutorotate {
return NO;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationPortrait;
}
I am not using a UINavigationController. When this UIViewController is being displayed, the device will still rotate to landscape. I am targeting iOS 9, what's the issue here?
So the issue was that I had defined the allowed orientations in info.plist which apparently overrides anything you do anywhere else throughout the project.
To correct the issue I removed the entries from info.plist and defined them in the project settings. Now everything works as expected.
I don't think Bryan's answer works,for changing the orientations in project settings also changes the info.plist as #mrhangz commented.
If the issue is iOS9 only,it is probably due to the new feature of iOS9 in iPad called Split view.The iOS9 enable Split view by default in particular iPad device,see Apple documents here.
The split view forced your app to support all orientations in all view once adoptted.So if you set all orientations support in either info.plist or target general setting,and then split view is supported by default,which will ignore the orientation setting though supportedInterfaceOrientations in your viewController and support all orientations.
As the document written,if you checked Requires full screen in your target settings,then your app will not support split view.Now you can control orientations in code again.
I have try many solution, but the correct answer with working solution is:
ios 8 and 9, no need to edit info.plist.
- (BOOL) shouldAutorotate {
return NO;
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return (UIInterfaceOrientationPortrait | UIInterfaceOrientationPortraitUpsideDown);
}
possible orientation
UIInterfaceOrientationUnknown
The orientation of the device cannot be determined.
UIInterfaceOrientationPortrait
The device is in portrait mode, with the device held upright and the home button on the bottom.
UIInterfaceOrientationPortraitUpsideDown
The device is in portrait mode but upside down, with the device held upright and the home button at the top.
UIInterfaceOrientationLandscapeLeft
The device is in landscape mode, with the device held upright and the home button on the left side.
UIInterfaceOrientationLandscapeRight
The device is in landscape mode, with the device held upright and the home button on the right side.
In swift 5
The code below will lock the current view controller into portrait mode but still allow the other view controllers to transition to landscape. I do believe that you have to enable all the orientations at the project level and then turn then "off" using this method but am not sure if there is way to turn them back "on" one by one.
private var _orientations = UIInterfaceOrientationMask.portrait
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
get { return self._orientations }
set { self._orientations = .portrait }
}
A more thorough explanation of it all can be found here:
The supportedInterfaceOrientations method doesn't override any method from its superclass
For simplicity, for iPad, if Supported interface orientations (iPad) property in info.plist includes all the four orientations, with UIRequiresFullScreen property value as NO, iOS will treat your app as supporting split view. If an app supports split view feature, you can not disable it from rotating, at least by the ways above.
I have a detail answer here.

How to get an iOS 7 iPhone app to rotate to all interface orientations?

I'm working on an iPhone app. Right now all my view controllers rotate to portrait, landscape left, and landscape right (default behavior for an iPhone app out of the box). What I want is for my app's setup, app-wide, to include support for all interface orientations. How do I make that happen? I have all interface orientations selected at the project level and it's not making any difference. Here's a pic:
Now, when I test my app on my iPhone, it refuses to rotate to UIInterfaceOrientationPortraitUpsideDown. Why?
Okay, once we get that figured out, there is a follow up question... I have a single view controller within my app that I only want to support UIInterfaceOrientationPortrait and UIInterfaceOrientationPortraitUpsideDown how can I achieve this? I have the following code in my controller and it doesn't do the trick:
// The following method never gets called (but wanted to
// include this to show that I've tried it).
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
// This method does get called but has no effect. The VC that this method
// belongs to rotates to all interface orientations except for
// UIInterfaceOrientationPortraitUpsideDown which is definitely
// not what I want...
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationPortrait | UIInterfaceOrientationPortraitUpsideDown;
}
// This method never gets called either and therefore has no effect...
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait) || (interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown);
}
Note that my app is storyboard based (if that makes any difference). Any help would be much appreciated! Thanks.
By doing what is explained in Landscape Mode ONLY for iPhone or iPad and adding evey interface orientation when doing it, it will support all orientations.
Change your App's Info.plist file:
Add Supported interface orientations row to your App's Info.plist file with all the supported interface orientation's
Add the supported interface orientation's to "Supported Interface Orientations".
(Targets -> YourApp -> Supported Interface Orientations -> Landscape Left & Right)

shouldAutorotateToInterfaceOrientation return YES

I often see code like this:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return YES;
}
If the supported orientation is set in the project configuration, wouldn't just returning YES all the time be pointless? Or are there certain cases where this has an effect?
shouldAutorotateToInterfaceOrientation: (which is deprecated since iOS 6, by the way) is something completely different than the UISupportedInterfaceOrientations in the info plist! If you don't implement this method, the respective view controller won't ever autorotate to that interface orientation, no matter what you specify in UISupportedInterfaceOrientations.
From the documentation of UISupportedInterfaceOrientations:
The system uses this information (along with the current device orientation) to choose the initial orientation in which to launch your app.
Maybe in many parts of your application you support multiple interface orientations, but in one part you only support some of them (for example you want a video only to play in landscape)
So even if your app supports portrait, you probably want that the viewcontroller makes the orientation landscape
Edit: i'm commenting here because I can't comment other answers.
#daniel-rinser in iOS6, the system checks for project supported interface orientations, and intersects with viewcontroller's supported orientations, so it isn't only for launch but for all app execution.

IOS6, MPMoivePlayerViewController and device orientation

My project set supported interface orientations to UIInterfaceOrientationMaskPortrait.
When I use presentMoviePlayerViewControllerAnimated: popup an MPMoivePlayerViewController, on IOS5 when I turn device, the controller will do auto orientation rotation, but on IOS6 it is always at portrait direction.
How can I make it act as IOS5?
Apple changed the way orientations are handle in iOS 6:
Controlling What Interface Orientations Are Supported (iOS 6)
When UIKit receives an orientation notification, it uses the
UIApplication object and the root view controller to determine whether
the new orientation is allowed. If both objects agree that the new
orientation is supported, then the user interface is rotated to the
new orientation. Otherwise the device orientation is ignored.
When a view controller is presented over the root view controller, the
system behavior changes in two ways. First, the presented view
controller is used instead of the root view controller when
determining whether an orientation is supported. Second, the presented
view controller can also provide a preferred orientation. If the view
controller is presented full screen, the user interface is presented
in the preferred orientation. The user is expected to see that the
orientation is different from the device orientation and rotate the
device. A preferred orientation is most often used when the content
must be presented in the new orientation.
So if your application is set to allow only portrait mode, you'll never get into landscape mode regardless of what any controller 'sais'.
See Controlling What Interface Orientations Are Supported (iOS 6) for more information.

iOS app orientation rotation lock / unlock by app's config

Hi,
I'm trying to implement orientation rotation lock / unlock toggle switch to my iOS app.
Locking is OK, but unlocking is a problem.
Suppose a situation that app's orientation and device's orientation are differ. If user unlocks in the situation, app's orientation should follow device's orientation immediately. But I cannot find the way.
How can I simulate device's orientation rotation?
Edit
I'll clarify the situation.
There is a toggle switch in app, enable/disable orientation rotation.
Step by step:
1. The switch is enabled.
2. Device rotates to portlait.
3. UIViewController's shouldAutorotateToInterfaceOrientation returns YES for every orientation.
4. App rotates to portlait.
5. User toggles the switch to disable.
6. Device rotates to landscape.
7. UIViewController's shouldAutorotateToInterfaceOrientation returns NO except portlait.
8. App doesn't rotate.
9. User toggles the switch to enable.
10. App should rotate to landscape. This is the problem.
I haven't tried it but there is a viewController method attemptRotationToDeviceOrientation (iOS5). Might be worth a shot. Interesting problem. Report back on if it works.
// call this method when your return value from shouldAutorotateToInterfaceOrientation: changes
// if the current interface orientation does not match the current device orientation,
// a rotation may occur provided all relevant view controllers now return YES from shouldAutorotateToInterfaceOrientation:
+ (void)attemptRotationToDeviceOrientation __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_5_0);
See my answer here: https://stackoverflow.com/a/13033443/580173
I made a custom UINavigationController, and there you can check in which view you are, and respond with the right masks. (I wanted the root view to be portrait)
- (BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
if([self.viewControllers count] == 1) return UIInterfaceOrientationMaskPortrait;
return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscape;
}
You could read "Technical Q&A QA1688" which deals with autoratotion and in every viewcontroller make the message shouldAutorotateToInterfaceOrientation: return the correct value depending on your switch setting. There is also a switch in your info.plist. Marke sure you have the correct settings here as well

Resources