简体   繁体   English

获取设备当前方向(应用扩展)

[英]Get device current orientation (App Extension)

How to get device current orientation in an App Extension, I have tried below two methods but no success.如何在应用程序扩展中获取设备当前方向,我尝试了以下两种方法但没有成功。

  1. It always return UIDeviceOrientationUnknown它总是返回 UIDeviceOrientationUnknown

     [[UIDevice currentDevice] orientation]
  2. It shows red message that 'sharedApplication' is not available on iOS (App Extension)它显示红色消息“sharedApplication”在 iOS 上不可用(应用程序扩展)

     [[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.那么现在如何才能获得当前的设备方向。

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: 编辑:在Swift 4上你可以这样做:

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
        }
    }
}

I found a way where we can calculate our device orientation like this way in (App Extension) 我找到了一种方法,我们可以这样计算我们的设备方向(App Extension)

- (void)viewDidLayoutSubviews
{
   if(self.view.frame.size.width > self.view.frame.size.height)
      NSLog(@"Landscape");
   else
      NSLog(@"Portrait");
}

It gives me right orientation but still not get as device is LandscapeLeft or LandscapeRight as well as Portrait or PortraitUpsideDown . 它给了我正确的方向,但仍然没有获得设备是LandscapeLeftLandscapeRight以及PortraitPortraitUpsideDown

Still need help. 仍然需要帮助。

The observer method will get called if you add this before: [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; 如果你之前添加它,将调用观察者方法: [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];

Edit: I use UIApplicationDidChangeStatusBarOrientationNotification for the observer 编辑:我为观察者使用UIApplicationDidChangeStatusBarOrientationNotification

And in my method I check: 在我的方法中,我检查:

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

Edit 2- Xcode 6.2 - iOS 7 & 8 编辑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. 似乎如果你想在iOS 7和8上使用它,上面的代码将在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. 所以我使用其他东西,因为在iOS 7上,mainScreen的界限永远不会改变,但是如果方向改变,iOS 8将会改变。

I've got 3 macros that will give me the right size of the screen's width & height regardless of the iOS version: 无论iOS版本如何,我都有3个宏可以为我提供正确尺寸的屏幕宽度和高度:

#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 这适用于iOS 7和iOS 8,但我没有检查旧版本的Xcode,只有6.2

This will return only if the device is on portrait or landscape, not all the 4 orientation types 仅当设备处于纵向或横向时才会返回,而不是所有4种方向类型

In BroadcastExtension you can use sampleBuffer to understand orientation: 在BroadcastExtension中,您可以使用sampleBuffer来理解方向:

if let orientationAttachment =  CMGetAttachment(sampleBuffer, RPVideoSampleOrientationKey as CFString, nil) as? NSNumber 
{  
          let orientation = CGImagePropertyOrientation(rawValue: orientationAttachment.uint32Value)   
}

You could take a look at this library and its forks . 你可以看看这个库及其分支 It uses CoreMotion to detect the device orientation so it may work on App Extension's restricted environment. 它使用CoreMotion来检测设备方向,因此它可以在App Extension的受限环境中运行。

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. addObserver:self.view错误,通知应附加在self以便被调用。 Work also on iOS8. 也适用于iOS8。

Use CoreMotion framework can get the device orientation. 使用CoreMotion框架可以获得设备方向。

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")
    }
}

I haven't been been able to get it to work in an iMessage App Extension. 我无法在iMessage App Extension中使用它。 Apple seems to have silently disabled it as far as I can tell. 据我所知,Apple似乎默默地禁用了它。 https://forums.developer.apple.com/thread/53981 https://forums.developer.apple.com/thread/53981

Handy extension method, just call UIInterfaceOrientation.current方便的扩展方法,只需调用UIInterfaceOrientation.current

extension UIInterfaceOrientation {
    static var current: UIInterfaceOrientation {
        return UIApplication.shared.windows.first?.windowScene?.interfaceOrientation ?? UIInterfaceOrientation.portrait
    }
}

此代码不会为您提供准确的UIDeviceOrientation,但您将能够知道它是纵向还是横向模式

BOOL isLandScape = !(self.view.frame.size.width == ([[UIScreen mainScreen] bounds].size.width*([[UIScreen mainScreen] bounds].size.width<[[UIScreen mainScreen] bounds].size.height))+([[UIScreen mainScreen] bounds].size.height*([[UIScreen mainScreen] bounds].size.width>[[UIScreen mainScreen] bounds].size.height)));

I have done in my custom keyboard extension,Hope It will help you.. 我已经完成了我的自定义键盘扩展,希望它会帮助你..

In order to update your custom keyboard when the orientation changes, override viewDidLayoutSubviews in the UIInputViewController. 要在方向更改时更新自定义键盘,请覆盖UIInputViewController中的viewDidLayoutSubviews。 In another word, we can say that viewDidLayoutSubviews always called when rotation done. 换句话说,我们可以说viewDidLayoutSubviews总是在旋转完成时调用。

In keyboard extension we're unable to use traditional flow as we usually used: 在键盘扩展中,我们无法像通常使用的那样使用传统流程:

[UIApplication sharedApplication] statusBarOrientation]

So to detect current orientation, I used following code: In Objc : 因此,为了检测当前方向,我使用了以下代码:在Objc中:

if([UIScreen mainScreen].bounds.size.width < [UIScreen mainScreen].bounds.size.height){
// Portrait Orientation
}
else{
//Landscape Orientation
}

And in swift4, you can use this: 在swift4中,您可以使用:

if UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height {
        //portrait Orientation
    }
    else
    {
        //landscape Orientation
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM