如何检测方位变化?

我正在使用Swift,我希望能够加载一个UIViewController,当我旋转到风景,任何人都可以指向正确的方向吗?

我无法在网上find任何东西,并有点困惑的文件。

以下是我如何工作:

didFinishLaunchingWithOptions函数里面的didFinishLaunchingWithOptions我把:

 NotificationCenter.default.addObserver(self, selector: #selector(AppDelegate.rotated), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) 

然后里面的AppDelegate类,我把以下function:

 func rotated() { if UIDeviceOrientationIsLandscape(UIDevice.current.orientation) { print("Landscape") } if UIDeviceOrientationIsPortrait(UIDevice.current.orientation) { print("Portrait") } } 

希望这可以帮助其他人!

谢谢!

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

使用UIDevice -orientation属性是不正确的(即使它可以在大多数情况下工作),并可能导致一些错误,例如UIDeviceOrientation也考虑设备的方向,如果面朝上或向下,没有直接的对在UIInterfaceOrientation枚举这些值。
此外,如果您以某种特定方向locking您的应用程序,UIDevice将为您提供设备定位而不考虑这一点。
另一方面,iOS8已经弃用了UIViewController类的interfaceOrientation属性。
有2个选项可用于检测接口方向:

  • 使用状态栏方向
  • 使用大小类,在iPhone上,如果他们没有被覆盖,他们可以给你一个方法来了解当前的界面方向

还缺less的是一种理解界面方向变化的方法,这在animation过程中非常重要。
在WWDC 2014的“View controller advancement in iOS8”中,演讲者还提供了解决该问题的方法, -will/DidRotateToInterfaceOrientation使用replace-will/DidRotateToInterfaceOrientation的方法。

这里提出的解决scheme部分实现,更多信息在这里 :

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

在使用带有AVFoundation的相机时需要检测旋转,并发现didRotate现在不推荐使用 )& willTransition方法对于我的需求是不可靠的。 使用David发布的通知确实有效,但对于Swift 3.x / 4.x不是最新的。

Swift 4.0随着Swift 4.0,Apple鼓励我们避免使用#selector ,所以这种方法现在使用完成块。 这种方法也向后兼容Swift 3.x&将是未来推荐的方法。

这是编译器警告,如果您使用#selector函数,您将在Swift 4.x项目中收到警告:

在这里输入图像描述

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

设置通知:

 NotificationCenter.default.addObserver(forName: .UIDeviceOrientationDidChange, object: nil, queue: .main, using: didRotate) 

把它撕下来:

 NotificationCenter.default.removeObserver(self, name: .UIDeviceOrientationDidChange, object: nil) 

Swift 3.0这是我以前的解决scheme,但我会build议使用上面的4.0解决scheme:

设置通知:

 NotificationCenter.default.addObserver(self, selector: #selector(rotated), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) 

回应通知:

 func rotated() { switch UIDevice.current.orientation { case .landscapeLeft, .landscapeRight: print("landscape") default: print("Portrait") } } 

撕下通知:

 NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) 

很简单,这个工作在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) } 

使用新的viewWillTransitionToSize(_:withTransitionCoordinator 🙂

我知道这个问题是针对Swift ,但是因为它是Googlesearch的顶级链接之一,所以如果您在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 } 

在目标C中

 -(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator 

迅速

 func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) 

重写此方法以检测方向更改。

全面实施如何检测Swift 3.0中的方向变化。

我select使用这种实现方式,因为face upface down手机方向对我来说很重要,而且只有当我知道方向在指定的位置时,我才想改变视图。

 import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //1 NotificationCenter.default.addObserver(self, selector: #selector(deviceOrientationDidChange), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) } deinit { //3 NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) } func deviceOrientationDidChange() { //2 switch UIDevice.current.orientation { case .faceDown: print("Face down") case .faceUp: print("Face up") case .unknown: print("Unknown") case .landscapeLeft: print("Landscape left") case .landscapeRight: print("Landscape right") case .portrait: print("Portrait") case .portraitUpsideDown: print("Portrait upside down") } } } 

重要的要注意的是:

  1. 您可以收听DeviceOrientationDidChange通知stream,并将其绑定到函数deviceOrientationDidChange
  2. 然后打开设备的方向,一定要注意有时候有一个unknown方向。
  3. 像任何通知一样,在viewController被取消初始化之前,一定要停止观察通知stream。

希望有人认为这有帮助。

 override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) { //swift 3 getScreenSize() } func getScreenSize(){ let screenWidth = UIScreen.main.bounds.width let screenHeight = UIScreen.main.bounds.height print("SCREEN RESOLUTION: \(screenWidth.description) x \(screenHeight.description)") } 

Swift 3 | UIDeviceOrientationDidChange观察到的通知太频繁

每当设备在3D空间中改变方向时,下面的代码都会打印“deviceDidRotate” – 无论纵向改变为横向。 例如,如果您以垂直方向握住手机,并向前和向后倾斜 – deviceDidRotate()将被重复调用。

 override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver( self, selector: #selector(deviceDidRotate), name: .UIDeviceOrientationDidChange, object: nil ) } func deviceDidRotate() { print("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") } 

或者,您可以使用不同的通知,只有当设备从横向更改为纵向时才会被调用。 在这种情况下,您想要使用UIApplicationDidChangeStatusBarOrientation通知。

 override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver( self, selector: #selector(deviceDidRotate), name: .UIApplicationDidChangeStatusBarOrientation, object: nil ) } func deviceDidRotate() { print("deviceDidRotate") } 

我喜欢检查方向通知,因为您可以在任何类中添加此function,不需要是视图或视图控制器。 即使在你的应用程序委托。

  //ask the system to start notifying when interface change UIDevice.currentDevice().beginGeneratingDeviceOrientationNotifications() //add the observer NSNotificationCenter.defaultCenter().addObserver( self, selector: #selector(self.orientationChanged(_:)), name: UIDeviceOrientationDidChangeNotification, object: nil) 

比caching通知

  func orientationChanged(notification : NSNotification) { //your code there } 

检查轮换是否改变了: viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)

使用coordinator.animateAlongsideTransition(nil) { (UIViewControllerTransitionCoordinatorContext)你可以检查转换是否完成。

见下面的代码:

 override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator) coordinator.animateAlongsideTransition(nil) { (UIViewControllerTransitionCoordinatorContext) in // if you want to execute code after transition finished print("Transition finished") } if size.height < size.width { // Landscape print("Landscape") } else { // Portrait print("Portrait") } } 

这是检测设备方向的简单方法:( Swift 3

 override func willRotate(to toInterfaceOrientation: UIInterfaceOrientation, duration: TimeInterval) { handleViewRotaion(orientation: toInterfaceOrientation) } //MARK: - Rotation controls func handleViewRotaion(orientation:UIInterfaceOrientation) -> Void { switch orientation { case .portrait : print("portrait view") break case .portraitUpsideDown : print("portraitUpsideDown view") break case .landscapeLeft : print("landscapeLeft view") break case .landscapeRight : print("landscapeRight view") break case .unknown : break } } 

对于Swift 3

 override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { if UIDevice.current.orientation.isLandscape { //Landscape } else { //Portrait } } 

我的方法类似于上面显示的,但是以iOS 9 +为重点。 我想在视图旋转时更改FSCalendar的范围。

 override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator) coordinator.animateAlongsideTransition({ (context) in if size.height < size.width { self.calendar.setScope(.Week, animated: true) self.calendar.appearance.cellShape = .Rectangle } else { self.calendar.appearance.cellShape = .Circle self.calendar.setScope(.Month, animated: true) } }, completion: nil) } 

这下面的工作,但我觉得羞怯的:)

 coordinator.animateAlongsideTransition({ (context) in if size.height < size.width { self.calendar.scope = .Week self.calendar.appearance.cellShape = .Rectangle } }) { (context) in if size.height > size.width { self.calendar.scope = .Month self.calendar.appearance.cellShape = .Circle } } 

我使用UIUserInterfaceSizeClass来检测在UIViewController类中更改的方向,就像那样:

 override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) { let isiPadLandscapePortrait = newCollection.horizontalSizeClass == .regular && newCollection.verticalSizeClass == .regular let isiPhonePlustLandscape = newCollection.horizontalSizeClass == .regular && newCollection.verticalSizeClass == .compact let isiPhonePortrait = newCollection.horizontalSizeClass == .compact && newCollection.verticalSizeClass == .regular let isiPhoneLandscape = newCollection.horizontalSizeClass == .compact && newCollection.verticalSizeClass == .compact if isiPhonePortrait { // do something... } } 
 - (void)viewDidLoad { [super viewDidLoad]; [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(OrientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil]; } -(void)OrientationDidChange:(NSNotification*)notification { UIDeviceOrientation Orientation=[[UIDevice currentDevice]orientation]; if(Orientation==UIDeviceOrientationLandscapeLeft || Orientation==UIDeviceOrientationLandscapeRight) { NSLog(@"Landscape"); } else if(Orientation==UIDeviceOrientationPortrait) { NSLog(@"Potrait Mode"); } } 

注:只需使用此代码来识别UIViewController是在哪个方向

Interesting Posts