在 Swift 中获取设备方向
Posted
技术标签:
【中文标题】在 Swift 中获取设备方向【英文标题】:Getting device orientation in Swift 【发布时间】:2014-11-05 22:33:07 【问题描述】:我想知道如何在 Swift 中获取当前设备方向?我知道有 Objective-C 的示例,但是我无法让它在 Swift 中运行。
我正在尝试获取设备方向并将其放入 if 语句中。
这是我遇到最多问题的一行:
[[UIApplication sharedApplication] statusBarOrientation]
【问题讨论】:
你的问题是什么?将其翻译成 Swift 或获得您期望的值? 设备方向不一定与您的 UI 方向匹配。案例点 - 将您的设备平放并测试您的代码! 【参考方案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.regular
和 height.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"
【讨论】:
以上是关于在 Swift 中获取设备方向的主要内容,如果未能解决你的问题,请参考以下文章