I already voted up the answer by @slycrel, but I would like to take the time to write this, and point some things out that seems to be lost in this old question, and lots of other questions on the subject.
It's true that Apple does not really want us to update most of our UI based on orientation changes, but it is still totally possible and sometimes necessary on a case by case scenario, and it will be that way until Apple improves their new(ish) APIs (e.g. viewWillTransitionToFrame:
would be way more useful than viewWillTransitionToSize:
. Just sayin')
Why I voted up the answer by @slycrel is related to what you need to keep in mind as the logical difference between UIDeviceOrientation
and UIInterfaceOrientation
.
Tthe status bar is what denotes an application's currently known UIInterfaceOrientation
. All this stuff about FaceUp
, FaceDown
is only related to a device's orientation, not necessarily your application's. An application does not support device orientations anyway. Really, UIDeviceOrientation
can be ignored completely if all you have to do is make sure you layout and animate things appropriately in your interface, which is 99% of an application developer's use cases. This is currently achieved with the status bar's UIInterfaceOrientation
from @slycrel's answer:
[UIApplication sharedApplication].statusBarOrientation
It should be noted, the readwrite version of this property is deprecated, the readonly version is not.
Take this example:
- I have an application that supports ALL interfaces orientations, and a root view controller that supports them as well.
- Now, I am presenting a
UIViewController
that will result in the status bar orientation to become landscape.
- Which landscape orientation (left or right) it goes to is based on what is returned by
preferredInterfaceOrientationForPresentation
for that view controller, what the current device orientation is, and what interface orientations the view controller supports (see next point).
- The status bar will go to landscape, regardless of what the current device orientation is, because this view controller only supports landscape based on what is returned by
supportedInterfaceOrientations
. Lets say we support both landscape left and right with UIInterfaceOrientationMaskLandscape
.
- I also want to conditionally animate this view controller into position with a rotation transform. This will only be necessary when going from portrait or portrait upside down, to landscape left or landscape right. Otherwise it will be a more simple presentation animation without rotation.
- Then, after some time and device use, I dismiss that view controller.
- Now I want to conditionally animate this view controller off the screen with another rotation transform. This will only be necessary when going from landscape left or landscape right, to portrait or portrait upside down. Otherwise it will be a more simple dismissal animation without rotation.
- At this point, the status bar's orientation will become whatever the system decides is appropriate for the combination of your root view controller's preferred interface orientation and supported interface orientations, as well as the device's current
UIDeviceOrientation
.
- Since the view controller we are going to supports ALL interface orientations, if your device's orientation is FaceUp or FaceDown, you can not reliably guess the next
UIInterfaceOrientation
based on UIDeviceOrientation
, and you do not have to anyway.
- So... status bar orientation to the rescue!
The previous example is possible, because the status bar orientation is not updated when a view controller transition is about to start (the system asks a transition delegate for an animator, etc.). Then it is updated when the transition starts animating (e.g. by the time animationTransition:
is called). This way you should have a good comparison just using the initial and current values of the status bar's UIInterfaceOrientation
.
Even without using view controller transitions, it should still be safe to update views based on the status bar orientation.
Keep in mind, if you are manually updating the status bar, and if you are not using "View controller-based status bar appearance" in your Info.plist, then your application's logic must be aware when the status bar will and did change orientation. You will probably be looking for a couple NSNotification
names for these cases, which are:
UIApplicationWillChangeStatusBarOrientationNotification
UIApplicationDidChangeStatusBarOrientationNotification
As well as these UIApplicationDelegate
methods:
- (void)application:(UIApplication *)application willChangeStatusBarOrientation:(UIInterfaceOrientation)newStatusBarOrientation duration:(NSTimeInterval)duration;
- (void)application:(UIApplication *)application didChangeStatusBarOrientation:(UIInterfaceOrientation)oldStatusBarOrientation;
- (UIInterfaceOrientationMask)supportedInterfaceOrientationsForWindow:(nullable UIWindow *)window
And this other helpful UIApplication
property:
@property(nonatomic,readonly) NSTimeInterval statusBarOrientationAnimationDuration;