iosobjective-cipaduiinterfaceorientation

How should I determine how to orient a view in landscape if the UIInterfaceOrientation landscape values are the same constant?


I want to present a view that responds to orientation changes but for various reasons can't use iOS's built-in autorotation. In viewDidLoad I use the current orientation to determine the initial layout of the view:

_originalOrientation = [UIDevice currentDevice].orientation;

// if we were launched flat or unknown, use the status bar orientation as a guide
if (_originalOrientation == UIDeviceOrientationUnknown ||
    _originalOrientation == UIDeviceOrientationFaceDown ||
    _originalOrientation == UIDeviceOrientationFaceUp) {

        _originalOrientation = UIDeviceOrientationFromInterfaceOrientation([UIApplication sharedApplication].statusBarOrientation);
}

As you can see from my comment, I need to handle the case where [UIDevice currentDevice].orientation is not a usable direction (i.e. the device is flat or in an unknown orientation). In this scenario, I attempt to use the statusBarOrientation to infer the device's orientation (using UIViewController's interfaceOrientation would be an alternative way to get the same information):

UIDeviceOrientation UIDeviceOrientationFromInterfaceOrientation(UIInterfaceOrientation interface) {
    // note: because UIInterfaceOrientationLandscapeLeft and UIInterfaceOrientationLandscapeRight have the same value, this conversion can't distinguish them

    if (interface == UIInterfaceOrientationLandscapeLeft) {
        return UIDeviceOrientationLandscapeLeft;

    } else if (interface == UIInterfaceOrientationLandscapeRight) {
        return UIDeviceOrientationLandscapeRight;

    } else if (interface == UIInterfaceOrientationPortraitUpsideDown) {
        return UIDeviceOrientationPortraitUpsideDown;

    } else {
        return UIDeviceOrientationPortrait;
    }
}

However my logic can't accurately discern the two landscape cases because they are defined UIApplication.h to be the same constant value:

// Note that UIInterfaceOrientationLandscapeLeft is equal to UIDeviceOrientationLandscapeRight (and vice versa).
// This is because rotating the device to the left requires rotating the content to the right.
typedef NS_ENUM(NSInteger, UIInterfaceOrientation) {
    UIInterfaceOrientationPortrait           = UIDeviceOrientationPortrait,
    UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
    UIInterfaceOrientationLandscapeLeft      = UIDeviceOrientationLandscapeRight,
    UIInterfaceOrientationLandscapeRight     = UIDeviceOrientationLandscapeLeft
};

Is there an alternative way I can distinguish between UIInterfaceOrientationLandscapeLeft and UIInterfaceOrientationLandscapeRight? Is there a better way for me to perform my "fallback" logic besides using the status bar orientation?


Solution

  • You wrote:

    However my logic can't accurately discern the two landscape cases because they are defined UIApplication.h to be the same constant value

    I am pretty sure that they are not! The values for interface and device orientations are swapped. See UIApplication.h:

    typedef NS_ENUM(NSInteger, UIInterfaceOrientation) {
        UIInterfaceOrientationPortrait           = UIDeviceOrientationPortrait,
        UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
        UIInterfaceOrientationLandscapeLeft      = UIDeviceOrientationLandscapeRight,
        UIInterfaceOrientationLandscapeRight     = UIDeviceOrientationLandscapeLeft
    };
    

    The interface orientation UIInterfaceOrientationLandscapeLeft is equal to the device orientation UIDeviceOrientationLandscapeRight, and vice versa. But:

    Try this code, I assume that will fix the problem:

    UIDeviceOrientation UIDeviceOrientationFromInterfaceOrientation(UIInterfaceOrientation interface) {
        // interface orientation left is device orientation right
        if (interface == UIInterfaceOrientationLandscapeLeft) {
            return UIDeviceOrientationLandscapeRight;
    
        // interface orientation right is device orientation left
        } else if (interface == UIInterfaceOrientationLandscapeRight) {
            return UIDeviceOrientationLandscapeLeft;
    
        } else if (interface == UIInterfaceOrientationPortraitUpsideDown) {
            return UIDeviceOrientationPortraitUpsideDown;
    
        } else {
            return UIDeviceOrientationPortrait;
        }
    }
    

    BTW, you should also consider to use an own prefix for your function instead of UI, otherwise it may be easy to mistakenly assume that UIDeviceOrientationFromInterfaceOrientation is an API function.