DeviceOrientation vs. ScreenSize vs StatusBar.isLandscape? --- NEW --- vs. SwuftUI GeometryReader?
SwiftUI 更新 - Xcode 12 和 iOS 16
如果您只想处理横向/纵向之间的变化,另一种 SwiftUI 的替代方案是在 ContentView 中拦截 geometryProxy,然后将值保存在全局变量中,以便在整个应用程序中使用。每次重新渲染 contentView 时,该值都会更新。这将使您避免观察 UIDevice 通知。
var content: some View {
GeometryReader { geometry in
processDeviceOrientation(with: geometry)
myContentView()
}
}
}
func processDeviceOrientation(with geometry: GeometryProxy) {
let orientation: DeviceOrientation = geometry.size.width > geometry.size.height ? .landscape : .portrait
if orientation != deviceOrientation {
deviceOrientation = orientation
}
}
}
var deviceOrientation: DeviceOrientation = .unknown
enum DeviceOrientation {
case landscape, portrait, unknown
}
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)")
}
这也发生在应用程序/视图控制器生命周期的早期阶段。
2. NotificationCenter
如果您需要获取实际设备方向(包括面朝下,面朝上等),您可以添加一个观察者如下(即使您在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:
print("unknown")
}
if orientation.isPortrait { print("isPortrait") }
if orientation.isLandscape { print("isLandscape") }
if orientation.isFlat { print("isFlat") }
}
请注意,
UIDeviceOrientationDidChangeNotification
可能会在启动过程中发布多次,并且在某些情况下可能是
.unknown
。 我所看到的是,在
viewDidLoad
和
viewWillAppear
方法之后,并且在
viewDidAppear
甚至在
applicationDidBecomeActive
之前,第一个正确的方向通知被接收到。
方向对象将提供您所有 7 种可能的情况(从
enum UIDeviceOrientation
的定义中):
public enum UIDeviceOrientation : Int {
case unknown
case portrait
case portraitUpsideDown
case landscapeLeft
case landscapeRight
case faceUp
case faceDown
}
有趣的是,只读的
Bool
变量
isPortrait
在扩展
UIDeviceOrientation
中定义如下:
extension UIDeviceOrientation {
public var isLandscape: Bool { get }
public var isPortrait: Bool { get }
public var isFlat: Bool { get }
public var isValidInterfaceOrientation: Bool { get }
}
3. StatusBarOrientation
UIApplication.shared.statusBarOrientation.isLandscape
这个方法同样适用于确定设备为纵向还是横向,并且与第一条方法得出的结果相同。您可以在
viewDidLoad
中(应用启动时)进行评估,以及在从后台返回时在
viewWillTransition(toSize:)
中进行评估。但是它不会像通知(Point 2)那样给你有关顶部/底部、左侧/右侧、上下的详细信息。
UIDeviceOrientationDidChangeNotification
来获取设备方向变化时的通知。 - sanUIApplication.sharedApplication().statusBarOrientation.isLandscape
是关于什么的? - aaisataevUIApplication.sharedApplication().statusBarOrientation
可以工作,但我想知道为什么在应用程序启动时UIDevice.currentDevice().orientation
不起作用。 - Joe HuangstatusBarOrientation
? - Joe Huang