ios 如何检测方向变化?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25666269/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to detect orientation change?
提问by David
I am using Swift and I want to be able to load a UIViewController when I rotate to landscape, can anyone point me in the right direction?
我正在使用 Swift 并且我希望能够在旋转到横向时加载 UIViewController,有人能指出我正确的方向吗?
I Can't find anything online and a little bit confused by the documentation.
我在网上找不到任何东西,并且对文档有点困惑。
回答by David
Here's how I got it working:
这是我如何让它工作的:
In AppDelegate.swift
inside the didFinishLaunchingWithOptions
function I put:
在 我放AppDelegate.swift
的didFinishLaunchingWithOptions
函数里面:
NotificationCenter.default.addObserver(self, selector: #selector(AppDelegate.rotated), name: UIDevice.orientationDidChangeNotification, object: nil)
and then inside the AppDelegate class I put the following function:
然后在 AppDelegate 类中,我放置了以下函数:
func rotated() {
if UIDeviceOrientationIsLandscape(UIDevice.current.orientation) {
print("Landscape")
}
if UIDeviceOrientationIsPortrait(UIDevice.current.orientation) {
print("Portrait")
}
}
Hope this helps anyone else!
希望这对其他人有帮助!
Thanks!
谢谢!
回答by Miros?aw ?wi?cicki
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
if UIDevice.current.orientation.isLandscape {
print("Landscape")
}
if UIDevice.current.orientation.isFlat {
print("Flat")
} else {
print("Portrait")
}
}
回答by CodeBender
Need to detect rotation while using the camera with AVFoundation
, and found that the didRotate
(now deprecated) & willTransition
methods were unreliable for my needs. Using the notification posted by David did work, but is not current for Swift 3.x/4.x.
需要在使用相机时检测旋转AVFoundation
,发现didRotate
(现已弃用)&willTransition
方法对我的需求不可靠。使用 David 发布的通知确实有效,但不适用于 Swift 3.x/4.x。
Swift 4.2The notification name has been changed.
Swift 4.2通知名称已更改。
The closure value remains the same as Swift 4.0:
闭包值与 Swift 4.0 相同:
var didRotate: (Notification) -> Void = { notification in
switch UIDevice.current.orientation {
case .landscapeLeft, .landscapeRight:
print("landscape")
case .portrait, .portraitUpsideDown:
print("Portrait")
default:
print("other")
}
}
To set up the notification for Swift 4.2:
为 Swift 4.2 设置通知:
NotificationCenter.default.addObserver(forName: UIDevice.orientationDidChangeNotification,
object: nil,
queue: .main,
using: didRotate)
To tear down the notification for Swift 4.2:
拆除 Swift 4.2 的通知:
NotificationCenter.default.removeObserver(self,
name: UIDevice.orientationDidChangeNotification,
object: nil)
Regarding the deprecation statement, my initial comment was misleading, so I wanted to update that. As noted, the usage of @objc
inference has been deprecated, which in turn was needed to use a #selector
. By using a closure instead, this can be avoided and you now have a solution that should avoid a crash due to calling an invalid selector.
关于弃用声明,我最初的评论具有误导性,所以我想更新一下。如前所述,@objc
推理的使用已被弃用,而使用#selector
. 通过改用闭包,可以避免这种情况,并且您现在有了一个解决方案,可以避免由于调用无效选择器而导致崩溃。
Everything below here is obsolete as of XCode 10 & iOS 4.2
从 XCode 10 和 iOS 4.2 开始,这里下面的所有内容都已过时
Swift 4.0With Swift 4.0, Apple has encouraged us to avoid using the #selector
, so this approach uses a completion block now. This approach is also backwards compatible with Swift 3.x & would be the recommended approach going forward.
Swift 4.0在 Swift 4.0 中,Apple 鼓励我们避免使用#selector
,因此这种方法现在使用完成块。这种方法也向后兼容 Swift 3.x & 将是推荐的方法。
This is the compiler warning you will receive in a Swift 4.x project if you use the #selector
function due to the deprecation of @objc
inference:
如果您#selector
由于@objc
推理的弃用而使用该函数,则这是您将在 Swift 4.x 项目中收到的编译器警告:
Entry in swift-evolution on this change.
Setup the callback:
设置回调:
// If you do not use the notification var in your callback,
// you can safely replace it with _
var didRotate: (Notification) -> Void = { notification in
switch UIDevice.current.orientation {
case .landscapeLeft, .landscapeRight:
print("landscape")
case .portrait, .portraitUpsideDown:
print("Portrait")
default:
print("other")
}
}
Setup the notification:
设置通知:
NotificationCenter.default.addObserver(forName: .UIDeviceOrientationDidChange,
object: nil,
queue: .main,
using: didRotate)
Tear it down:
拆下来:
NotificationCenter.default.removeObserver(self, name: .UIDeviceOrientationDidChange, object: nil)
回答by Andrea
Using -orientation
property of UIDevice
is not correct (even if it could work in most of cases) and could lead to some bugs, for instance UIDeviceOrientation
consider also the orientation of the device if it is face up or down, there is no direct pair in UIInterfaceOrientation
enum for those values.
Furthermore, if you lock your app in some particular orientation, UIDevice will give you the device orientation without taking that into account.
On the other side iOS8 has deprecated the interfaceOrientation
property on UIViewController
class.
There are 2 options available to detect the interface orientation:
使用-orientation
of 属性UIDevice
是不正确的(即使它在大多数情况下都可以工作)并且可能会导致一些错误,例如UIDeviceOrientation
还要考虑设备的方向,如果它是面朝上或朝下,UIInterfaceOrientation
枚举中没有直接对值。
此外,如果您将应用锁定在某个特定方向,UIDevice 将在不考虑设备方向的情况下为您提供设备方向。
另一方面,iOS8 已经弃用了classinterfaceOrientation
上的属性UIViewController
。
有 2 个选项可用于检测界面方向:
- Use the status bar orientation
- Use size classes, on iPhone if they are not overridden they could give you a way to understand the current interface orientation
- 使用状态栏方向
- 使用大小类,在 iPhone 上,如果它们没有被覆盖,它们可以让您了解当前的界面方向
What is still missing is a way to understand the direction of a change of interface orientation, that is very important during animations.
In the session of WWDC 2014 "View controller advancement in iOS8" the speaker provides a solution to that problem too, using the method that replaces -will/DidRotateToInterfaceOrientation
.
仍然缺少的是一种理解界面方向变化方向的方法,这在动画中非常重要。
在 WWDC 2014“iOS8 中的视图控制器改进”的会议中,演讲者也提供了该问题的解决方案,使用替换 -will/DidRotateToInterfaceOrientation
.
Here the proposed solution partially implemented, more info here:
这里建议的解决方案部分实现,更多信息在这里:
func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
let orientation = orientationFromTransform(coordinator.targetTransform())
let oldOrientation = UIApplication.sharedApplication().statusBarOrientation
myWillRotateToInterfaceOrientation(orientation,duration: duration)
coordinator.animateAlongsideTransition({ (ctx) in
self.myWillAnimateRotationToInterfaceOrientation(orientation,
duration:duration)
}) { (ctx) in
self.myDidAnimateFromInterfaceOrientation(oldOrientation)
}
}
回答by mikeho
I know this question is for Swift
, but since it's one of the top links for a Google search and if you're looking for the same code in Objective-C
:
我知道这个问题是针对 的Swift
,但由于它是 Google 搜索的热门链接之一,并且如果您正在寻找相同的代码Objective-C
:
// add the observer
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(rotated:) name:UIDeviceOrientationDidChangeNotification object:nil];
// remove the observer
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
// method signature
- (void)rotated:(NSNotification *)notification {
// do stuff here
}
回答by Josh
Easy, this works in iOS8 and 9 / Swift 2 / Xcode7, just put this code inside your viewcontroller.swift. It will print the screen dimensions with every orientation change, you can put your own code instead:
很简单,这适用于 iOS8 和 9 / Swift 2 / Xcode7,只需将此代码放在您的 viewcontroller.swift 中即可。它会在每次方向更改时打印屏幕尺寸,您可以使用自己的代码:
override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation) {
getScreenSize()
}
var screenWidth:CGFloat=0
var screenHeight:CGFloat=0
func getScreenSize(){
screenWidth=UIScreen.mainScreen().bounds.width
screenHeight=UIScreen.mainScreen().bounds.height
print("SCREEN RESOLUTION: "+screenWidth.description+" x "+screenHeight.description)
}
回答by Aditya Wirayudha
回答by Mahendra
In Objective C
在目标 C
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
In swift
在迅速
func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
Override this method to detect the orientation change.
覆盖此方法以检测方向变化。
回答by Alberto Scampini
I like checking the orientation notification because you can add this feature in any class, no needs to be a view or a view controller. Even in your app delegate.
我喜欢检查方向通知,因为您可以在任何类中添加此功能,无需是视图或视图控制器。即使在您的应用程序委托中。
SWIFT 5:
快速 5:
//ask the system to start notifying when interface change
UIDevice.current.beginGeneratingDeviceOrientationNotifications()
//add the observer
NotificationCenter.default.addObserver(
self,
selector: #selector(orientationChanged(notification:)),
name: UIDevice.orientationDidChangeNotification,
object: nil)
than caching the notification
比缓存通知
@objc func orientationChanged(notification : NSNotification) {
//your code there
}
回答by Derek Soike
Swift 3 | UIDeviceOrientationDidChange Notification Observed Too Often
斯威夫特 3 | 经常观察到 UIDeviceOrientationDidChange 通知
The following code prints "deviceDidRotate" every time your device changes orientation in 3D space - regardless of a change from portrait to landscape orientation. For example, if you hold your phone in portrait orientation and tilt it forward and backward - deviceDidRotate() is called repeatedly.
每当您的设备在 3D 空间中更改方向时,以下代码都会打印“deviceDidRotate” - 无论从纵向更改为横向。例如,如果您以纵向方向握住手机并将其前后倾斜 - deviceDidRotate() 将被重复调用。
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(deviceDidRotate),
name: .UIDeviceOrientationDidChange,
object: nil
)
}
func deviceDidRotate() {
print("deviceDidRotate")
}
To work around this you could hold the previous device orientation and check for a change in deviceDidRotate().
要解决此问题,您可以保持先前的设备方向并检查 deviceDidRotate() 中的更改。
var previousDeviceOrientation: UIDeviceOrientation = UIDevice.current.orientation
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(deviceDidRotate),
name: .UIDeviceOrientationDidChange,
object: nil
)
}
func deviceDidRotate() {
if UIDevice.current.orientation == previousDeviceOrientation { return }
previousDeviceOrientation = UIDevice.current.orientation
print("deviceDidRotate")
}
Or you can use a different notification that only gets called when the device changes from landscape to portrait. In this case you'd want to use the UIApplicationDidChangeStatusBarOrientation
notification.
或者您可以使用不同的通知,该通知仅在设备从横向变为纵向时才被调用。在这种情况下,您希望使用UIApplicationDidChangeStatusBarOrientation
通知。
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(deviceDidRotate),
name: .UIApplicationDidChangeStatusBarOrientation,
object: nil
)
}
func deviceDidRotate() {
print("deviceDidRotate")
}