【问题标题】:In 7.3/9/2+ Swift how to disable rotation animation, when device rotates?在 7.3/9/2+ Swift 中,当设备旋转时如何禁用旋转动画?
【发布时间】:2016-11-17 18:48:48
【问题描述】:

这个问题完全是关于iOS9+的

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

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

但您只希望在用户旋转设备期间没有动画。您希望它“点击”到新的横向或竖直布局。

我能够做到这一点的唯一方法是添加:

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 中使用)来打开和关闭动画。

但是问题很多

  • 这在 AppWide 中不起作用,一团糟,它是基于场景的

  • 关闭所有动画似乎非常糟糕

  • 你可以看到各种各样的赛道

这个问题完全是关于iOS9+的

这些天来,有没有更好的方法可以在支持横向/纵向的应用中关闭旋转动画???

这个问题完全是关于iOS9+的

【问题讨论】:

  • 这适用于哪个版本的 iOS?
  • 嗨@LukeVanIn 谢谢,当然是iOS9。注意第一句话!
  • 在模拟器上工作,但不能在真实设备(ipad)上工作。 UIView.areAnimationsEnabled() 在动画块内返回true,这让我很困惑(因为它之前确实被禁用了)。旋转动画块一定有时间问题...(setAnimationsEnabled doc 状态:“此方法仅影响调用后提交的那些动画。如果在现有动画运行时调用此方法,这些动画会继续运行,直到它们到达自然终点。")

标签: ios swift ios9 ios-autolayout autorotate


【解决方案1】:

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

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

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 方法调用。

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

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

【讨论】:

  • 您需要在您的应用中声明这个新类一次,然后将您的所有视图控制器声明从class MyViewController: UIViewController {...} 更改为MyViewController: NoRotateAnimationVC {...}
  • 啊,你是说每个视图控制器都必须这样做。很公平。有趣的是,我发现如果你只选择一个 - 我认为甚至是随机的 - 它确实有效。 (我不知道这是否会带来更多问题。)再次感谢
  • @JoeBlow 当您旋转设备时,所有需要更改其视图大小的视图控制器都会收到viewWillTransitionToSize 方法调用。提供的实现禁用所有动画并在转换后重新启用它们。因此,如果您仅在一个 View Controller 中覆盖此方法,只要其视图会因旋转而改变大小,它就会在任何地方禁用旋转动画。但如果该视图控制器未处于活动状态,动画将不会被禁用。
  • 感谢您的精彩解释,bzz。说得通!我想如果它是“顶级”的,并且你知道它总是在应用程序中,那么可以这样做。再次感谢。
  • 我可以在控制器之间(而不是在控制器内)转换时禁用旋转动画吗? stackoverflow.com/questions/42743526/…
【解决方案2】:

您可以使用方法调配

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

带着那份悲伤,你应该非常谨慎的调酒,强大的力量伴随着巨大的责任。将类放在您或您之后的下一个程序员知道如何找到它的地方,当他想要将旋转动画返回给视图控制器时。

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

【讨论】:

  • 不要认为这在 Swift 5 中不再有效
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-07
  • 1970-01-01
相关资源
最近更新 更多