【问题标题】:In Swift, how to get the device orientation correctly right after it's launched?在 Swift 中,如何在启动后立即正确获取设备方向?
【发布时间】:2020-06-08 02:06:08
【问题描述】:

我使用以下代码查看设备是否处于横向模式:

UIDevice.currentDevice().orientation.isLandscape.boolValue

如果我在启动应用程序之前将设备置于横向模式,并且在viewDidLoad 之后调用这行代码,它总是返回false

如果我改用这个:

interfaceOrientation.isLandscape

它返回true,这是正确的,但编译器显示警告interfaceOrientation was deprecated in iOS 8.0

在应用启动后立即获取设备方向的正确方法是什么?

【问题讨论】:

  • 你的应用只支持一个方向?
  • 该应用支持纵向和横向。我将设备置于横向模式,第一行返回 false。如果我旋转,它会开始返回正确的值。
  • interfaceOrientation 和 deviceOrientation 是两个不同的东西。使用UIDeviceOrientationDidChangeNotification 在设备方向发生变化时得到通知
  • UIApplication.sharedApplication().statusBarOrientation.isLandscape怎么样
  • @san 我可以毫无问题地获得方向通知。我想知道应用启动时的方向。

标签: ios swift swift2 orientation uiinterfaceorientation


【解决方案1】:

DeviceOrientation vs. ScreenSize vs StatusBar.isLandscape?

iOS 11、Swift 4 和 Xcode 9.X

无论是否使用 AutoLayout,有几种方法可以获得正确的设备方向,它们可用于在使用应用时检测旋转变化,以及在应用启动时或从后台恢复后获得正确的方向.

此解决方案在 iOS 11 和 Xcode 9.X 中运行良好

1. UIScreen.main.bounds.size: 如果您只想知道应用程序是处于横向还是纵向模式,则最好在启动时在viewDidLoad 中的rootViewController 中开始,如果您想检测旋转,则在rootViewController 中的viewWillTransition(toSize:)应用在后台时会发生变化,并且应该以正确的方向恢复 UI。

let size = UIScreen.main.bounds.size
if size.width < size.height {
    print("Portrait: \(size.width) X \(size.height)")
} else {
    print("Landscape: \(size.width) X \(size.height)")
}

这也发生在 app/viewController 生命周期的早期。

2。通知中心

如果您需要获取实际的设备方向(包括 faceDown、faceUp 等)。您想按如下方式添加观察者(即使您在AppDelegate 中的application:didFinishLaunchingWithOptions 方法中执行此操作,也可能会在执行viewDidLoad 后触发第一个通知

device = UIDevice.current
device?.beginGeneratingDeviceOrientationNotifications()
notificationCenter = NotificationCenter.default
notificationCenter?.addObserver(self, selector: #selector(deviceOrientationChanged),
    name: Notification.Name("UIDeviceOrientationDidChangeNotification"),
    object: nil)

并添加选择器如下。我将它分成两部分,以便能够在 viewWillTransition 中运行 inspectDeviceOrientation()

@objc func deviceOrientationChanged() {
    print("Orientation changed")
    inspectDeviceOrientation()
}

func inspectDeviceOrientation() {
    let orientation = UIDevice.current.orientation
    switch UIDevice.current.orientation {
    case .portrait:
        print("portrait")
    case .landscapeLeft:
        print("landscapeLeft")
    case .landscapeRight:
        print("landscapeRight")
    case .portraitUpsideDown:
        print("portraitUpsideDown")
    case .faceUp:
        print("faceUp")
    case .faceDown:
        print("faceDown")
    default: // .unknown
        print("unknown")
    }
    if orientation.isPortrait { print("isPortrait") }
    if orientation.isLandscape { print("isLandscape") }
    if orientation.isFlat { print("isFlat") }
}

请注意,UIDeviceOrientationDidChangeNotification 在发布期间可能会发布多次,在某些情况下可能是.unknown。我所看到的是,在viewDidLoadviewWillAppear 方法之后,以及在viewDidAppear 甚至applicationDidBecomeActive 之前收到了第一个正确的方向通知

方向对象将为您提供所有 7 种可能的场景(来自 enum UIDeviceOrientation 定义):

public enum UIDeviceOrientation : Int {
    case unknown
    case portrait // Device oriented vertically, home button on the bottom
    case portraitUpsideDown // Device oriented vertically, home button on the top
    case landscapeLeft // Device oriented horizontally, home button on the right
    case landscapeRight // Device oriented horizontally, home button on the left
    case faceUp // Device oriented flat, face up
    case faceDown // Device oriented flat, face down
}

有趣的是,isPortrait 只读变量BoolUIDeviceOrientation 的扩展中定义如下:

extension UIDeviceOrientation {
    public var isLandscape: Bool { get }
    public var isPortrait: Bool { get }
    public var isFlat: Bool { get }
    public var isValidInterfaceOrientation: Bool { get }
}

3.状态栏方向

UIApplication.shared.statusBarOrientation.isLandscape 

这也可以很好地确定方向是纵向还是横向,并给出与第 1 点相同的结果。您可以在 viewDidLoad(用于应用程序启动)和 viewWillTransition(toSize:)(如果来自背景)进行评估。但它不会为您提供您通过通知获得的上/下、左/右、上/下的详细信息(第 2 点)

【讨论】:

  • #3 对我来说效果很好 - 我想要两个不同的状态,横向与纵向,以便进行一些非常具体的 UI 更新。当设备变平时,使用设备方向会搞砸。
【解决方案2】:

这对我有用:

if UIScreen.main.bounds.width > UIScreen.main.bounds.height{
    print("Portraitmode!")
}

它适用于基于显示尺寸的所有设备: https://developer.apple.com/library/archive/documentation/DeviceInformation/Reference/iOSDeviceCompatibility/Displays/Displays.html

【讨论】:

    【解决方案3】:

    我测试过很多次方向,所以总结了一些经验。

    在所有 iPhone 设备中,除了 iPhone6(s) plus,唯一的界面方向是.portrait。如果应用程序以横向模式启动,则必须改变方向。一个人将收到UIDeviceOrientationDidChangeNotification。现在是获得方向的合适时机。

    关于iPhone6横屏启动,启动后的方向会改变一次:

    在 iPhone6 plus 横向启动时,启动后方向从未改变:

    同一个应用的两张不同截图,

    所以在应用确实改变方向之前,方向仍然和主页一样。

    viewDidLoad,方向还没有改变,日志会是错误的方向。

    【讨论】:

      【解决方案4】:

      在检查方向isLandscape 之前,应检测isValidInterfaceOrientation不要处理带有 isValidInterfaceOrientation == false 的平面消息(当它具有isLandscape 的任何值时)。

      在我更仔细地阅读该主题之前,我对此很感兴趣。考虑到isValidInterfaceOrientation,它工作正常。

      @objc func rotated() {
          if (UIDevice.current.orientation.isValidInterfaceOrientation) {
              if (UIDevice.current.orientation.isLandscape) { 
                  if(!bLandscape) {
                      bLandscape = true
                      setupTabBar() // Repaint the app
                  }
              } else { // Portait 
                  if(bLandscape) {
                      bLandscape = false
                      setupTabBar() // Repaint the app 
                  }
              }
          }
      }
      

      【讨论】:

      • 当手机方向被锁定时,这个解决方案对我不起作用。我想在手机方向被锁定时检测方向变化。有没有可行的方法?
      【解决方案5】:

      我在检测 isFlat 之前的方向时遇到问题,所以我把它放在我的视图控制器中

      let orientation = UIDevice.current.orientation
      
      override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
          if  orientation.isPortrait {
              return .portrait
          } else if orientation.isFlat{
              if UIScreen.main.bounds.width < UIScreen.main.bounds.height{
                  return .portrait
              } else {
                  return .landscape
              }
          } else {
              return .landscape
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2014-11-05
        • 1970-01-01
        • 2014-04-18
        • 1970-01-01
        • 2016-12-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多