【问题标题】:Get device current orientation (App Extension)获取设备当前方向(应用扩展)
【发布时间】:2014-08-23 12:49:24
【问题描述】:

如何在应用扩展中获取设备当前方向,我尝试了以下两种方法,但都没有成功。

  1. 它总是返回 UIDeviceOrientationUnknown

    [[UIDevice currentDevice] orientation]
    
  2. 它显示红色消息“sharedApplication”在 iOS 上不可用(应用程序扩展)

    [[UIApplication sharedApplication] statusBarOrientation];
    
  3. 我还添加了一个观察者,但它没有被调用。

    [[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"];
    }
    

那么现在任何人如何才能获得当前的设备方向。

【问题讨论】:

标签: ios objective-c keyboard ios-app-extension uideviceorientation


【解决方案1】:

我有个主意!

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

}

编辑:在 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
        }
    }
}

【讨论】:

  • 这是我见过的最好的答案。在扩展上下文和常规应用上下文中都可以完美运行,并且可以区分横向左侧和横向右侧。干得好!
  • 天才!像魅力一样工作。
  • 这总是给我所有方向的肖像。
【解决方案2】:

我在(App Extension)

中找到了一种可以像这样计算设备方向的方法
- (void)viewDidLayoutSubviews
{
   if(self.view.frame.size.width > self.view.frame.size.height)
      NSLog(@"Landscape");
   else
      NSLog(@"Portrait");
}

它给了我正确的方向,但仍然没有得到,因为设备是 LandscapeLeftLandscapeRight 以及 PortraitPortraitUpsideDown强>。

仍然需要帮助。

【讨论】:

  • 任何投我反对票的人,您是否首先实际尝试过。首先检查这个stackoverflow.com/questions/24166878/…,并在这里解释你为什么要投票给我。
  • 您应该使用屏幕边界而不是视图框架,因为它并不总是正确的,在我的情况下,视图宽度总是大于高度,但使用屏幕边界对我有用 CGRect r = [UIScreen mainScreen].bounds; BOOL isLandscape = r.size.width > r.size.height;
【解决方案3】:

如果你之前添加了这个,观察者方法将被调用: [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];

编辑:我使用UIApplicationDidChangeStatusBarOrientationNotification 作为观察者

我用我的方法检查:

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

编辑 2- Xcode 6.2 - iOS 7 & 8

如果你想在 iOS 7 和 8 上都使用这个,上面的代码会在 iOS 7 上给你错误的结果。

所以我使用了其他东西,因为在 iOS 7 上,mainScreen 的边界永远不会改变,但在 iOS 8 上,如果方向改变就会改变。

无论 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)

然后,当通知被触发时,我会像这样检查方向:

BOOL isPortrait = SCREEN_WIDTH_CALCULATED < SCREEN_HEIGHT_CALCULATED;

这适用于 iOS 7 和 iOS 8,但我没有检查旧版本的 Xcode,只有 6.2

仅当设备处于纵向或横向时才会返回,而不是所有 4 种方向类型

【讨论】:

  • 我编辑了我的答案,也许它会对你有所帮助。我使用 Xcode 6.1 进行了测试,并且可以正常工作。
  • 完成这个答案,还有UIDeviceOrientationDidChangeNotification
  • 我这样做了,但是每次调用UIApplicationDidChangeStatusBarOrientationNotification 时,似乎都认为它的方向相同;即 UIDevice.currentDevice().orientation == 0。(UIDeviceOrientationDidChangeNotification 对我来说根本不起作用)
  • 我试过这个,但它总是认为它是横向的。它不起作用:(
  • 设备方向事件不会在应用扩展中发送
【解决方案4】:

在 BroadcastExtension 中,您可以使用 sampleBuffer 来了解方向:

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

【讨论】:

    【解决方案5】:

    您可以查看this 库及其forks。它使用 CoreMotion 来检测设备方向,因此它可以在 App Extension 的受限环境中工作。

    【讨论】:

      【解决方案6】:

      我知道已经晚了,但是这个问题的错误在这一行:

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

      addObserver:self.view 错误,通知应附在self 上以便被调用。也适用于 iOS8。

      【讨论】:

      • 好的,我会检查这个,你确定你是在“应用程序扩展”中这样做
      • 不,你是对的,我正在寻找标准应用程序。顺便看看这个答案,也许它也适用于 App Extension:stackoverflow.com/a/24467241/1171614
      【解决方案7】:

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

      【讨论】:

        【解决方案8】:

        我无法让它在 iMessage 应用程序扩展中工作。据我所知,Apple 似乎已经默默地禁用了它。 https://forums.developer.apple.com/thread/53981

        【讨论】:

          【解决方案9】:

          方便的扩展方法,只需调用UIInterfaceOrientation.current

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

          【讨论】:

            【解决方案10】:

            此代码不会为您提供确切的 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)));
            

            【讨论】:

              【解决方案11】:

              我已经完成了我的自定义键盘扩展,希望对你有所帮助..

              为了在方向改变时更新您的自定义键盘,请覆盖 UIInputViewController 中的 viewDidLayoutSubviews。换句话说,我们可以说 viewDidLayoutSubviews 总是在旋转完成时调用。

              在键盘扩展中,我们无法使用我们通常使用的传统流程:

              [UIApplication sharedApplication] statusBarOrientation]
              

              所以为了检测当前方向,我使用了以下代码: 在对象中:

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

              在 swift4 中,你可以使用这个:

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2018-08-16
                • 1970-01-01
                • 1970-01-01
                • 2017-08-25
                • 1970-01-01
                相关资源
                最近更新 更多