如何检测方向变化?

Dav*_*vid 142 orientation-changes ios swift

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

我在网上找不到任何东西,文档也有点困惑.

Dav*_*vid 186

以下是我如何使用它:

在 我放AppDelegate.swiftdidFinishLaunchingWithOptions功能里面:

NotificationCenter.default.addObserver(self, selector: #selector(AppDelegate.rotated), name: UIDevice.orientationDidChangeNotification, object: nil)
Run Code Online (Sandbox Code Playgroud)

然后在AppDelegate类里面我放了以下函数:

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

    if UIDeviceOrientationIsPortrait(UIDevice.current.orientation) {
        print("Portrait")
    }
}
Run Code Online (Sandbox Code Playgroud)

希望这有助于其他任何人!

谢谢!

  • 要小心,因为`UIDeviceOrientation`与`UIInterfaceOrientation`是不同的.这是因为`UIDeviceOrientation`还检测面朝下和面朝上的方向,这意味着如果你的设备在几乎平坦的情况下休息,你的代码可以随意地在纵向和横向之间跳转表面稍微不平整(即在6/6的突出相机上摇摆) (21认同)
  • 我尝试在AppDelegate中添加addObserver,但在CoreFoundation中使用无法识别的选择器继续获取SIGABRT.但是,当我在第一个视图中将addObserver移动到viewDidLoad时,它工作得很好.仅供参考,如果有人遇到同样的问题. (5认同)
  • 我非常肯定只有你接受参数(旋转()`没有) (4认同)
  • 如果手机禁用自动旋转,此方法不起作用. (4认同)

小智 172

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")
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这将在轮换之前调用.如果您需要例如旋转后的框架尺寸,此解决方案将无法工作. (65认同)
  • 在iPad上,因为大小等级对于横向和纵向都是相同的,所以从不调用此方法. (5认同)
  • 如果手机禁用自动旋转,此方法不起作用. (4认同)
  • 不需要"boolValue" - "isLandscape"已经是Bool (3认同)

Cod*_*der 58

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

Swift 4.2 通知名称已更改.

闭包值与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")
        }
    }
Run Code Online (Sandbox Code Playgroud)

要设置Swift 4.2的通知:

NotificationCenter.default.addObserver(forName: UIDevice.orientationDidChangeNotification,
                                       object: nil,
                                       queue: .main,
                                       using: didRotate)
Run Code Online (Sandbox Code Playgroud)

要删除Swift 4.2的通知:

NotificationCenter.default.removeObserver(self,
                                          name: UIDevice.orientationDidChangeNotification,
                                          object: nil)
Run Code Online (Sandbox Code Playgroud)

关于弃用声明,我的初步评论具有误导性,所以我想更新一下.如上所述,@objc推理的使用已被弃用,而这又需要使用#selector.通过使用闭包,可以避免这种情况,现在您可以使用一个解决方案来避免因调用无效选择器而导致崩溃.

从XCode 10和iOS 4.2开始,这里的所有内容都已过时

Swift 4.0 使用Swift 4.0,Apple鼓励我们避免使用#selector,因此这种方法现在使用完成块.这种方法也向后兼容Swift 3.x并且将是未来推荐的方法.

如果#selector由于@objc推断的弃用而使用该函数,那么您将在Swift 4.x项目中收到编译器警告:

在此输入图像描述

快速进化这一变化.

设置回调:

// 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")
        }
    }
Run Code Online (Sandbox Code Playgroud)

设置通知:

NotificationCenter.default.addObserver(forName: .UIDeviceOrientationDidChange,
                                       object: nil,
                                       queue: .main,
                                       using: didRotate)
Run Code Online (Sandbox Code Playgroud)

撕下来:

NotificationCenter.default.removeObserver(self, name: .UIDeviceOrientationDidChange, object: nil)
Run Code Online (Sandbox Code Playgroud)

  • 你有没有提到苹果谈论阻止在Swift 4中使用#selector的地方?我想了解他们为什么这么说. (4认同)

And*_*rea 18

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

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

仍然缺少的是一种理解界面方向变化方向的方法,这在动画期间非常重要.
在WWDC 2014"在iOS8中查看控制器进展"的会话中,扬声器也使用替换的方法提供了该问题的解决方案 -will/DidRotateToInterfaceOrientation.

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

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)
        }
    }
Run Code Online (Sandbox Code Playgroud)


mik*_*eho 11

我知道这个问题适用于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
}
Run Code Online (Sandbox Code Playgroud)


Jos*_*osh 11

简单,这适用于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)
    }
Run Code Online (Sandbox Code Playgroud)

  • 不推荐使用此函数,请改用"viewWillTransitionToSize:withTransitionCoordinator:" (5认同)

Pat*_*tar 9

从 iOS 8 开始,这是正确的方法。

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)

    coordinator.animate(alongsideTransition: { context in
        // This is called during the animation
    }, completion: { context in
        // This is called after the rotation is finished. Equal to deprecated `didRotate`
    })
}
Run Code Online (Sandbox Code Playgroud)


Mah*_*dra 8

在目标C中

-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
Run Code Online (Sandbox Code Playgroud)

在迅速

func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
Run Code Online (Sandbox Code Playgroud)

覆盖此方法以检测方向更改.


Der*_*ike 8

斯威夫特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")
}
Run Code Online (Sandbox Code Playgroud)

要解决此问题,您可以保留先前的设备方向并检查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")
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用仅在设备从横向更改为纵向时才会调用的其他通知.在这种情况下,您需要使用UIApplicationDidChangeStatusBarOrientation通知.

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

func deviceDidRotate() {
    print("deviceDidRotate")
}
Run Code Online (Sandbox Code Playgroud)


Alb*_*ini 6

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

SWIFT 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)
Run Code Online (Sandbox Code Playgroud)

比缓存通知

    @objc func orientationChanged(notification : NSNotification) {
        //your code there
    }
Run Code Online (Sandbox Code Playgroud)


Jee*_*dhi 6

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)")
}
Run Code Online (Sandbox Code Playgroud)


Rob*_*ack 6

如何检测Swift 3.0中的方向更改的完整工作实现.

我选择使用这个实现,因为手机的方向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")
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

需要注意的重要事项是:

  1. 您收听DeviceOrientationDidChange通知流并将其绑定到函数deviceOrientationDidChange
  2. 然后打开设备方向,请务必注意unknown有时会出现方向.
  3. 与任何通知一样,在取消初始化viewController之前,请确保停止观察通知流.

希望有人觉得这很有帮助.


小智 6

斯威夫特 4:

override func viewWillAppear(_ animated: Bool) {
    NotificationCenter.default.addObserver(self, selector: #selector(deviceRotated), name: UIDevice.orientationDidChangeNotification, object: nil)
}

override func viewWillDisappear(_ animated: Bool) {
    NotificationCenter.default.removeObserver(self, name: UIDevice.orientationDidChangeNotification, object: nil)
}

@objc func deviceRotated(){
    if UIDevice.current.orientation.isLandscape {
        //Code here
    } else {
        //Code here
    }
}
Run Code Online (Sandbox Code Playgroud)

当需要跨各种视图控制器进行检测时,很多答案都无济于事。这个可以解决问题。


Dav*_*rew 5

如果你想在旋转完成后做一些事情,你可以UIViewControllerTransitionCoordinator像这样使用完成处理程序

public override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)

    // Hook in to the rotation animation completion handler
    coordinator.animate(alongsideTransition: nil) { (_) in
        // Updates to your UI...
        self.tableView.reloadData()
    }
}
Run Code Online (Sandbox Code Playgroud)