Get device current orientation (App Extension)

2020-02-04 11:42发布

How to get device current orientation in an App Extension, I have tried below two methods but no success.

  1. It always return UIDeviceOrientationUnknown

    [[UIDevice currentDevice] orientation]
    
  2. It shows red message that ‘sharedApplication’ is not available on iOS (App Extension)

    [[UIApplication sharedApplication] statusBarOrientation];
    
  3. I also add an observer but it not getting called.

    [[NSNotificationCenter defaultCenter] addObserver:self.view selector:@selector(notification_OrientationWillChange:) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
    
    
    
    - (void)notification_OrientationWillChange:(NSNotification*)n
    {
       UIInterfaceOrientation orientation = (UIInterfaceOrientation)[[n.userInfo objectForKey:UIApplicationStatusBarOrientationUserInfoKey] intValue];
    
        if (orientation == UIInterfaceOrientationLandscapeLeft)
           [self.textDocumentProxy insertText:@"Left"];
        if (orientation == UIInterfaceOrientationLandscapeRight)
           [self.textDocumentProxy insertText:@"Right"];
    }
    

So now how can anyone get current device orientation.

10条回答
淡お忘
2楼-- · 2020-02-04 12:34

I know it's late, but the mistake in this question was in this line:

[[NSNotificationCenter defaultCenter] addObserver:self.view selector:@selector(notification_OrientationWillChange:) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];

addObserver:self.view is wrong, the notification should be attached on self for being called. Work also on iOS8.

查看更多
smile是对你的礼貌
3楼-- · 2020-02-04 12:38

I got an idea!

extension UIScreen {

    var orientation: UIInterfaceOrientation {
        let point = coordinateSpace.convertPoint(CGPointZero, toCoordinateSpace: fixedCoordinateSpace)
        if point == CGPointZero {
            return .Portrait
        } else if point.x != 0 && point.y != 0 {
            return .PortraitUpsideDown
        } else if point.x == 0 && point.y != 0 {
            return .LandscapeLeft
        } else if point.x != 0 && point.y == 0 {
            return .LandscapeRight
        } else {
            return .Unknown
        }
    }

}

EDIT: On Swift 4 you can do:

extension UIScreen {
    var orientation: UIInterfaceOrientation {
        let point = coordinateSpace.convert(CGPoint.zero, to: fixedCoordinateSpace)
        switch (point.x, point.y) {
        case (0, 0):
            return .portrait
        case let (x, y) where x != 0 && y != 0:
            return .portraitUpsideDown
        case let (0, y) where y != 0:
            return .landscapeLeft
        case let (x, 0) where x != 0:
            return .landscapeRight
        default:
            return .unknown
        }
    }
}
查看更多
Ridiculous、
4楼-- · 2020-02-04 12:44

The observer method will get called if you add this before: [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];

Edit: I use UIApplicationDidChangeStatusBarOrientationNotification for the observer

And in my method I check:

UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; BOOL isPortrait = UIDeviceOrientationIsPortrait(orientation);

Edit 2- Xcode 6.2 - iOS 7 & 8

It seems that if you want to use this on both iOS 7 & 8, the code above will give you wrong result on iOS 7.

So I use something else because on iOS 7 the mainScreen's bounds will never change, but on iOS 8 will change if the orientation changes.

I've got 3 macros that will give me the right size of the screen's width & height regardless of the iOS version:

#define IOS_VERSION_OLDER_THAN_8 ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.0)

#define SCREEN_WIDTH_CALCULATED (IOS_VERSION_OLDER_THAN_8 ? (UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation) ? [[UIScreen mainScreen] bounds].size.width : [[UIScreen mainScreen] bounds].size.height) : [[UIScreen mainScreen] bounds].size.width)

#define SCREEN_HEIGHT_CALCULATED (IOS_VERSION_OLDER_THAN_8 ? (UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation) ? [[UIScreen mainScreen] bounds].size.height : [[UIScreen mainScreen] bounds].size.width) : [[UIScreen mainScreen] bounds].size.height)

Then, when the notification is fired, i check the orientation like this:

BOOL isPortrait = SCREEN_WIDTH_CALCULATED < SCREEN_HEIGHT_CALCULATED;

This will work on iOS 7 & iOS 8, but i didn't check for older versions of Xcode, only 6.2

This will return only if the device is on portrait or landscape, not all the 4 orientation types

查看更多
爷、活的狠高调
5楼-- · 2020-02-04 12:45

Use CoreMotion framework can get the device orientation.

func startMonitorDeviceOrientation() {
    if motionManager.isDeviceMotionAvailable {
        motionManager.deviceMotionUpdateInterval = 1.0
        let queue = OperationQueue()

        motionManager.startDeviceMotionUpdates(to: queue) { (deviceMotion, error) in
            guard let x = deviceMotion?.gravity.x,
            let y = deviceMotion?.gravity.y
            else {
                return
            }

            if fabs(y) >= fabs(x) {
                if y >= 0 {
                    // UIDeviceOrientationPortraitUpsideDown;
                    print("device orientation UIDeviceOrientationPortraitUpsideDown")
                } else {
                    // UIDeviceOrientationPortrait;
                    print("device orientation UIDeviceOrientationPortrait")
                }
            } else {
                if x >= 0 {
                    // UIDeviceOrientationLandscapeRight;
                    print("device orientation UIDeviceOrientationLandscapeRight")
                } else {
                    // UIDeviceOrientationLandscapeLeft;
                    print("device orientation UIDeviceOrientationLandscapeLeft")
                }
            }
        }
    } else {
        print("Device motion is not avaliable")
    }
}
查看更多
登录 后发表回答