在Swift中获取设备方向

96

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

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

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

[[UIApplication sharedApplication] statusBarOrientation]

你的问题是什么?是将其翻译成Swift还是获得您期望的值? - David Rönnqvist
1
设备方向不一定与您的UI方向匹配。举个例子 - 将您的设备平放并测试您的代码! - Patrick
20个回答

8

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弃用警告。 - Jav Solo
3
你正在调用 super.viewWillAppear 而不是 super.viewDidAppear。 - 7RedBits.com
非常好用 - 谢谢 - Iain Coleman

5

UIDevice.current.orientation在我的指南针类型应用程序中无法工作,因为它报告手机水平时显示“面朝上”或“面朝下”,而不管屏幕的方向如何。我想显示用户的方向,假设他们以自然方向拿着手机。

UIApplication.shared.statusBarOrientation给了我一个已弃用的警告“'statusBarOrientation'在iOS 13.0中被弃用:改用窗口场景的interfaceOrientation属性。”

以下内容符合我的需求。

var headingOffset = 0.0
        
let scenes = UIApplication.shared.connectedScenes
let windowScene = scenes.first as? UIWindowScene
        
switch windowScene?.interfaceOrientation {
case .portrait:
   headingOffset = 0.0
   print("Reporting orientation as portrait")
case .portraitUpsideDown:
   headingOffset = 180.0
   print("Reporting orientation as portraitUpsideDown")
case .landscapeLeft:
   headingOffset = -90.0
    print("Reporting orientation as landscapeLeft")
case .landscapeRight:
   headingOffset = 90.0
   print("Reporting orientation as landscapeRight")
default:
   headingOffset = 0.0
   print("Reporting orientation as default")
}

4

我发现Swift中可以用另一种代码替代Obj-C中的代码

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

if UIApplication.shared.statusBarOrientation.isLandscape

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

4

基于Rob的回答,Swift 3

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

2
在你的重载函数中别忘了调用 super.viewWillTransition(to: size, with: coordinator) - Bocaxica

3
   override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
    if (toInterfaceOrientation.isLandscape) {
        NSLog("Landscape");
    }
    else {
        NSLog("Portrait");
    }
}

3

Swift 5

适用于SwiftUI和基于storyboard的应用程序。同时,检查旋转和特征处理程序

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

1

对于任何在iOS 13之后看到这篇文章的人:

目前最可靠的方法已经被弃用,但仍然可以使用:

print(UIApplication.shared.statusBarOrientation.isPortrait)

现在似乎要走的路线是什么:
if UIApplication.shared.windows.first?.
windowScene?.interfaceOrientation.isPortrait ?? true {
    print("Portrait")
} else {
    print("Landscape")
}

1

我认为在现代的Objective C中,考虑到现在已经弃用的函数,最好的方法是...

UIDeviceOrientationIsLandscape([[UIDevice currentDevice] orientation]);

在Swift中,那就是这样的。
UIDevice.current.orientation.isLandscape

1

保持简单:

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

0
尝试使用horizontalSizeClassverticalSizeClass:
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")
                }
            }
        }
    }
}

在这个教程中找到了它。相关的苹果文档


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接