【问题标题】:Getting device orientation in Swift在 Swift 中获取设备方向
【发布时间】:2014-11-05 22:33:07
【问题描述】:

我想知道如何在 Swift 中获取当前设备方向?我知道有 Objective-C 的示例,但是我无法让它在 Swift 中运行。

我正在尝试获取设备方向并将其放入 if 语句中。

这是我遇到最多问题的一行:

[[UIApplication sharedApplication] statusBarOrientation]

【问题讨论】:

  • 你的问题是什么?将其翻译成 Swift 或获得您期望的值?
  • 设备方向不一定与您的 UI 方向匹配。案例点 - 将您的设备平放并测试您的代码!

标签: ios swift orientation


【解决方案1】:

你可以使用:

override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation) {
    var text=""
    switch UIDevice.currentDevice().orientation{
    case .Portrait:
        text="Portrait"
    case .PortraitUpsideDown:
        text="PortraitUpsideDown"
    case .LandscapeLeft:
        text="LandscapeLeft"
    case .LandscapeRight:
        text="LandscapeRight"
    default:
        text="Another"
    }
    NSLog("You have moved: \(text)")        
}

SWIFT 3 更新

override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) {
    var text=""
    switch UIDevice.current.orientation{
    case .portrait:
        text="Portrait"
    case .portraitUpsideDown:
        text="PortraitUpsideDown"
    case .landscapeLeft:
        text="LandscapeLeft"
    case .landscapeRight:
        text="LandscapeRight"
    default:
        text="Another"
    }
    NSLog("You have moved: \(text)")        
}

override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
}

您可以通过通知查看:IOS8 Swift: How to detect orientation change?

注意: didRotateFromInterfaceOrientation 已弃用 viewWillTransitionToSize 适用于 iOS 2.0 及更高版本

在面朝上和面朝下的情况下,这将不起作用。 所以我们需要使用以下内容。

if UIApplication.shared.statusBarOrientation.isLandscape {
     // activate landscape changes
} else {
     // activate portrait changes
}

【讨论】:

  • 感谢您的分享!
  • 嗯...如果用户在旋转后导航到此视图,我们将不知道起始方向...
  • 如果您仍在使用此功能,尽管它已被弃用。不要忘记在你的实现中调用它的超级方法。即:super.didRotate(from: fromInterfaceOrientation)。来自 Apple 文档:“您对此方法的实现必须在其执行期间的某个时间点调用 super。”
【解决方案2】:

要像您拥有的 Objective-C 代码一样获得状态栏(以及 UI)方向,只需:

UIApplication.sharedApplication().statusBarOrientation

也可以使用 UIDevice 的orientation property

UIDevice.currentDevice().orientation

但是,这可能与您的 UI 的方向不匹配。来自文档:

该属性的值是一个常数,表示当前 设备的方向。这个值代表物理 设备的方向,可能与当前不同 应用程序用户界面的方向。看 “UIDeviceOrientation”用于描述可能的值。

【讨论】:

  • UIApplication.sharedApplication().statusBarOrientation 仅在主线程上
  • 感谢您的帮助!
  • 我正在使用 uidevice.current.orientation.isportrait 检查设备方向并更改应用程序的用户界面,但即使将设备放在桌面上,它也会发生变化。但多亏了你,现在它工作得很好
  • 在 swift 5.1 上更新 -> UIDevice.current.orientation
  • 如果设备方向为面朝上或面朝下,UIDevice.current.orientation.isPortrait 不起作用。像这个答案一样检查状态栏一直是一致的并且对我有用。
【解决方案3】:

Apple 最近摆脱了横向与纵向的概念,更喜欢我们使用屏幕尺寸。但是,这是可行的:

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    if UIDevice.currentDevice().orientation.isLandscape.boolValue {
        print("landscape")
    } else {
        print("portrait")
    }
}

【讨论】:

  • 我会在您的解决方案中注意到苹果声明:“如果您在自定义视图控制器中覆盖此方法,请始终在您的实现中的某个时刻调用 super”
【解决方案4】:
struct DeviceInfo {
struct Orientation {
    // indicate current device is in the LandScape orientation
    static var isLandscape: Bool {
        get {
            return UIDevice.current.orientation.isValidInterfaceOrientation
                ? UIDevice.current.orientation.isLandscape
                : UIApplication.shared.statusBarOrientation.isLandscape
        }
    }
    // indicate current device is in the Portrait orientation
    static var isPortrait: Bool {
        get {
            return UIDevice.current.orientation.isValidInterfaceOrientation
                ? UIDevice.current.orientation.isPortrait
                : UIApplication.shared.statusBarOrientation.isPortrait
        }
    }
}}

swift4 答案: 我就是这样做的,

1.适用于各种视图控制器

2.当用户旋转应用时也可以工作

3.也是第一次安装应用

【讨论】:

  • 完美答案!谢谢
  • 很好,但为什么你写它拖时间而不是@objc class var isLandscape: Bool { return !isPortrait } 我没有得到重要的东西? ;)
  • 哇,它工作得很好,因为我不会......非常感谢你:)
  • 我怎么知道方向改变了?
【解决方案5】:

斯威夫特 4:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        if UIDevice.current.orientation.isLandscape {
            print("landscape")
        } else {
            print("portrait")
        }
    }

【讨论】:

  • isFlat 方向怎么样?
  • 不要忘记在覆盖函数的某个位置调用 super.viewWillTransition(to: size, with: coordinator)。
【解决方案6】:

要查找当前设备方向,只需使用以下代码:

UIApplication.sharedApplication().statusBarOrientation

对于 Swift 3.0

UIApplication.shared.statusBarOrientation

【讨论】:

  • iPad air 1&2 返回错误值,iPad 2 和 iPhone 正确。我真的很想找到一个适用于所有设备的设备,但苹果在这里搞得一团糟! :(
  • UIDevice.current.orientation 不同,UIApplication.shared.statusBarOrientation 在初始加载时可用,而不是在屏幕旋转后才可用。
【解决方案7】:

我在使用 InterfaceOrientation 时遇到了问题,它工作正常,只是它没有访问加载时的方向。所以我尝试了这个,它是一个守门员。这是因为 bounds.width 始终参考当前方向,而不是绝对的 nativeBounds.width

    if UIScreen.mainScreen().bounds.height > UIScreen.mainScreen().bounds.width {
        // do your portrait stuff
    } else {    // in landscape
        // do your landscape stuff
    }

我从willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval)viewDidLoad 调用它,但它很灵活。

感谢 zSprawl 提供指向该方向的指针。我应该指出,这仅适用于 iOS 8 及更高版本。

【讨论】:

  • 不适用于 iOS 9 & 10 iPad,只有初始值是正确的,以下所有值都是相反的方向。
  • @Steven.B 嗯...在我的 iPad Air、iPad 3 和 iOS 9 下的模拟器上运行良好。还与 beta 测试人员一起使用。也许您还使用了其他影响这一点的代码。
  • 此代码可能仅在 UIViewcontroller 中使用时有效,我试图在自定义 UIView 类中获取方向和边界,但是当方向正确时,几乎我测试的每个设备都返回不同的值框架或边界仍然错误。
【解决方案8】:

因此,如果 Apple 不赞成使用整个方向字符串(“portrait”、“landscape”),那么您所关心的只是宽度与高度的比率。 (有点像@bpedit 的回答)

当你将宽度除以高度时,如果结果小于 1,那么 mainScreen 或容器或任何处于“肖像”“模式”的东西。如果结果大于 1,则为“风景”画。 ;)

override func viewWillAppear(animated: Bool) {
    let size: CGSize = UIScreen.mainScreen().bounds.size
    if size.width / size.height > 1 {
        print("landscape")
    } else {
        print("portrait")
    }
}
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    if size.width / size.height > 1 {
        print("landscape")
    } else {
        print("portrait")
    }
}

(我猜如果您使用这种方法,那么您可能并不真正关心当比率恰好为 1、宽度和高度相等时的具体处理条件。)

【讨论】:

  • 不错!对您的答案的小改进:不要忘记在您的覆盖函数中的某个时间点调用 super.viewWillAppear(animated)super.viewWillTransition(to: size, with: coordinator)
【解决方案9】:

斯威夫特 3+

基本上:

NotificationCenter.default.addObserver(self, selector: #selector(self.didOrientationChange(_:)), name: .UIDeviceOrientationDidChange, object: nil)

@objc func didOrientationChange(_ notification: Notification) {
    //const_pickerBottom.constant = 394
    print("other")
    switch UIDevice.current.orientation {
        case .landscapeLeft, .landscapeRight:
            print("landscape")
        case .portrait, .portraitUpsideDown:
            print("portrait")
        default:
            print("other")
    }
}

:)

【讨论】:

  • 我喜欢这个答案。这对于像 iPad 这样的大屏幕非常有用,因为 traitcollection 将始终为 width.regularheight.regular,因此 traitCollection 不会在旋转时改变。在 Swift 4 中,通知已重命名为 UIDevice.orientationDidChangeNotification
  • 这就是我要找的。对于 Swift 4 及更高版本,使用如下:let notificationCenter = NotificationCenter.default notificationCenter.addObserver(self, selector: #selector(self.didOrientationChange(_:)), name: UIDevice.orientationDidChangeNotification, object: nil)
【解决方案10】:

statusBarOrientation弃用,因此不再可用像 在以上答案

在这段代码中可以得到方向而不用担心折旧。 斯威夫特 5 iOS 13.2 100% 测试

您的应用程序应该允许纵向和横向工作以使用以下代码,否则结果会有所不同

windows.first 是主窗口 windows.last 是您的当前窗口

struct Orientation {
    // indicate current device is in the LandScape orientation
    static var isLandscape: Bool {
        get {
            return UIDevice.current.orientation.isValidInterfaceOrientation
                ? UIDevice.current.orientation.isLandscape
                : (UIApplication.shared.windows.first?.windowScene?.interfaceOrientation.isLandscape)!
        }
    }
    // indicate current device is in the Portrait orientation
    static var isPortrait: Bool {
        get {
            return UIDevice.current.orientation.isValidInterfaceOrientation
                ? UIDevice.current.orientation.isPortrait
                : (UIApplication.shared.windows.first?.windowScene?.interfaceOrientation.isPortrait)!
        }
    }
}

【讨论】:

    【解决方案11】:

    Swift 3,基于 Rob 的回答

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        if (size.width / size.height > 1) {
            print("landscape")
        } else {
            print("portrait")
        }
    }
    

    【讨论】:

    • 不要忘记在覆盖函数中的某个时刻调用super.viewWillTransition(to: size, with: coordinator)
    【解决方案12】:

    我发现 Swift 中的 Obj-C 代码的替代代码

    if (UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) 
    

    if UIApplication.shared.statusBarOrientation.isLandscape
    

    注意:我们正在尝试查找状态栏方向是否为横向。如果是横向,则 if 语句为真。

    【讨论】:

      【解决方案13】:
         override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
          if (toInterfaceOrientation.isLandscape) {
              NSLog("Landscape");
          }
          else {
              NSLog("Portrait");
          }
      }
      

      【讨论】:

        【解决方案14】:

        Swift 5 – 解决方案:在应用启动和设备旋转期间检查方向:

        // app start
        override func viewDidAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
            if let orientation = self.view.window?.windowScene?.interfaceOrientation {
                let landscape = orientation == .landscapeLeft || orientation == .landscapeRight
            }
        }
        
        // on rotation
        override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
            super.viewWillTransition(to: size, with: coordinator)
            let landscape = UIDevice.current.orientation == .landscapeLeft || UIDevice.current.orientation == .landscapeRight
        }
        

        【讨论】:

        • 这个答案消除了我在 OS 15 目标中的 windows 弃用警告
        • 你调用的是 super.viewWillAppear 而不是 super.viewDidAppear
        【解决方案15】:

        斯威夫特 5

        适用于 SwiftUI 和基于故事板的应用程序。另外,检查旋转和特征处理程序

        struct Orientation {
            
            /// true - if landscape orientation, false - else
            static var isLandscape: Bool {
                orientation?.isLandscape ?? window?.windowScene?.interfaceOrientation.isLandscape ?? false
            }
            
            /// true - if portrait orientation, false - else
            static var isPortrait: Bool {
                orientation?.isPortrait ?? (window?.windowScene?.interfaceOrientation.isPortrait ?? false)
            }
            
            /// true - if flat orientation, false - else
            static var isFlat: Bool {
                orientation?.isFlat ?? false
            }
            
            /// valid orientation or nil
            static var orientation: UIDeviceOrientation? {
                UIDevice.current.orientation.isValidInterfaceOrientation ? UIDevice.current.orientation : nil
            }
            
            /// Current window (for both SwiftUI and storyboard based app)
            static var window: UIWindow? {
                guard let scene = UIApplication.shared.connectedScenes.first,
                      let windowSceneDelegate = scene.delegate as? UIWindowSceneDelegate,
                      let window = windowSceneDelegate.window else {
                    return UIApplication.shared.windows.first
                }
                return window
            }
        }
        
        class ViewController: UIViewController {
            
            override func viewWillAppear(_ animated: Bool) {
                super.viewWillAppear(animated)
                layoutAll()
            }
        
            override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
                super.viewWillTransition(to: size, with: coordinator)
                print("viewWillTransition")
                layoutAll()
            }
            
            override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
                super.traitCollectionDidChange(previousTraitCollection)
                print("traitCollectionDidChange")
                layoutAll()
            }
            
            /// Layout content depending on the orientation
            private func layoutAll() {
                // Layout as you need
                print("layoutAll: isLandscape=\(Orientation.isLandscape), isPortrait=\(Orientation.isPortrait), traitCollection=\(traitCollection)")
            }
        }
        

        【讨论】:

          【解决方案16】:

          尝试使用horizontalSizeClass & verticalSizeClass

          import SwiftUI
          
          struct DemoView: View {
              
              @Environment(\.horizontalSizeClass) var hSizeClass
              @Environment(\.verticalSizeClass) var vSizeClass
              
              var body: some View {
                  VStack {
                      if hSizeClass == .compact && vSizeClass == .regular {
                          VStack {
                              Text("Vertical View")
                          }
                      } else {
                          HStack {
                              Text("Horizontal View")
                          }
                      }
                  }
              }
          }
          

          tutorial 中找到它。相关苹果的documentation

          【讨论】:

            【解决方案17】:

            对于任何看到过去 iOS 13 的人:

            对我来说最可靠的方法现在已被弃用,尽管它(仍然)有效:

            print(UIApplication.shared.statusBarOrientation.isPortrait)
            

            现在看来要走的路:

            if UIApplication.shared.windows.first?.
            windowScene?.interfaceOrientation.isPortrait ?? true {
                print("Portrait")
            } else {
                print("Landscape")
            }
            

            【讨论】:

              【解决方案18】:

              保持简单:

              let orientation = UIApplication.shared.statusBarOrientation.isLandscape ? "landscape" : "portrait"
              

              【讨论】:

                猜你喜欢
                • 2014-10-28
                • 1970-01-01
                • 1970-01-01
                • 2018-09-30
                • 2012-07-04
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多