在 7.3/9/2+ Swift 设备旋转时如何禁用旋转动画?

In 7.3/9/2+ Swift how to disable rotation animation, when device rotates?

这个问题严格来说是关于 iOS9+

假设您有一个普通的现代应用程序(自动布局、故事板、通用),它允许所有四个旋转位置

您希望它以正常方式自动旋转,因此当用户将设备从横向旋转为纵向时,它会更改为新的基于约束的布局

但是您只是希望在用户旋转设备期间没有动画。您希望它只是 "click" 到新的横向或直立布局。

我能够实现这一点的唯一方法是添加:

override func viewWillTransitionToSize(size:CGSize,
       withTransitionCoordinator coordinator:UIViewControllerTransitionCoordinator)
    {
    coordinator.animateAlongsideTransition(nil, completion:
        {_ in
        UIView.setAnimationsEnabled(true)
        })
    UIView.setAnimationsEnabled(false)
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator);
    }

一个视图控制器,一个最高或接近最高的VC,它包含其余的容器视图或场景中的任何内容。

这与使用 willRotateToInterfaceOrientation/didRotateFromInterfaceOrientation(两者现在在现代 iOS 中都无法使用)打开和关闭动画。

然而问题很多

这个问题严格来说是关于 iOS9+

现在支持landscape/portrait的app有没有更好的关闭旋转动画的方法???

这个问题严格来说是关于 iOS9+

据我所知,没有更好的方法了。

尽管您可以使用此方法声明一个单独的 class 并将应用中的所有视图控制器设为其子class。

class NoRotateAnimationVC: UIViewController {
    override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
        UIView.setAnimationsEnabled(false)
        coordinator.notifyWhenInteractionEndsUsingBlock {_ in UIView.setAnimationsEnabled(true)}
    }
}

当您旋转设备时,所有需要更改其视图大小的视图控制器都会收到 viewWillTransitionToSize 方法调用。

您需要在您的应用中声明这个新的 class 一次,然后将所有视图控制器声明从 class MyViewController: UIViewController 更改为 MyViewController: NoRotateAnimationVC.

提供的实现禁用所有动画并在转换后重新启用它们。因此,如果您仅在一个视图控制器中重写此方法,只要其视图会因旋转而改变大小,它就会禁用所有位置的旋转动画。但是,如果该视图控制器未处于活动状态,则不会禁用动画。

您可以使用方法调配

这意味着将在您的应用程序中的任何视图控制器上将对 "viewWillTransitionToSize" 的调用更改为调用 "genericViewWillTransitionToSize"。
这样您就不必在应用程序中使用 subclass 或重复代码。

既然如此难过,就要小心谨慎,能力越大,责任越大。将 class 放在您或您之后的下一个程序员知道如何找到它的地方,当他想要 return 旋转动画以查看控制器时。

extension UIViewController {

    public override static func initialize() {
        struct Static {
            static var token: dispatch_once_t = 0
        }

        dispatch_once(&Static.token) {
            let originalSelector = #selector(UIViewController.viewWillTransitionToSize(_:withTransitionCoordinator:))
            let swizzledSelector = #selector(UIViewController.genericViewWillTransitionToSize(_:withTransitionCoordinator:))

            let originalMethod = class_getInstanceMethod(self, originalSelector)
            let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)

            let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))

            if didAddMethod {
                class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
            } else {
                method_exchangeImplementations(originalMethod, swizzledMethod);
            }
        }
    }

    // MARK: - Method Swizzling
    func genericViewWillTransitionToSize(size:CGSize,
                                           withTransitionCoordinator coordinator:UIViewControllerTransitionCoordinator)
    {
        self.genericViewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
        coordinator.animateAlongsideTransition(nil, completion:
            {_ in
                UIView.setAnimationsEnabled(true)
        })
        UIView.setAnimationsEnabled(false)
    }
}