Device Orientation in iOS
Let me tell you a story: there once was an iOS app that was primarily locked into a portrait orientation, but had a photo viewer that could support landscape. The systems for governing orientation were complex and not clearly explained anywhere, and clear answers on Stack Overflow were hard to come by.
In the end, we figured it out. The trickiest part was figuring out how to keep the app from launching in a forbidden orientation, but still allow the orientation in the photo viewer. Here's what we learned.
Project Settings > General > Deployment Info
This is easy. For each targeted device, select orientations that the app can be launched into. If the device is in an orientation that isn't included here when the app is launched, it will snap to one that is.
View Controller Orientation Methods
The app's root view controller has some methods for controlling rotation.
In iOS 5 (and before), -(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
is used. It overrides the orientations listed in the project's Deployment Info.
In iOS 6 (and later), we instead use -(NSUInteger)supportedInterfaceOrientations
and return a UIInterfaceOrientationMask
value.
However, in iOS 6 and later, supportedInterfaceOrientations
does NOT override the settings in Deployment Info, but rather can be used to disable orientations enumerated in the Deployment Info.
App Delegate
In iOS 6 (and later), there is an optional method that can be implemented in the App Delegate: -(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
. If implemented, this will kick in after the app launches, and override the orientations listed in the Deployment Info.
So, in our example, we want the app limited to portrait at launch and throughout the app, except in the photo viewer.
In Deployment Info, only portrait is allowed.
For iOS 6 and later, application:supportedInterfaceOrientationsForWindow:
overrides the Deployment Info (once the app is launched) by returning UIInterfaceOrientationMaskAll
.
The root view controller is set up to call shouldAutorotateToInterfaceOrientation:
and supportedInterfaceOrientations
on the top view controller on the stack and return the result.
In iOS 5, shouldAutorotateToInterfaceOrientation:
returns YES
only if interfaceOrientation
is UIInterfaceOrientationPortrait
, except in the case of the view controller for the photo viewer, which always returns YES
.
In iOS 6, supportedInterfaceOrientations
returns UIInterfaceOrientationMaskPortrait
, except the photo viewer, which returns UIInterfaceOrientationMaskAll
.