【问题标题】:Keep animation when changing viewController更改 viewController 时保持动画
【发布时间】:2018-05-23 15:04:57
【问题描述】:

我正在尝试在个人资料图片后面编码animation,以鼓励用户点击它。 这是一个越来越大的圆圈。

override func layoutSubviews() {
  super.layoutSubviews()

  UIView.animate(withDuration: 1.0, delay: 0, options: [.repeat, .autoreverse], animations: {

     self.bouncedView.transform = CGAffineTransform(scaleX:
        1.3, y: 1.3)

      }, completion: nil)

}

问题是,当我转到另一个viewController 时,动画停止并且圆圈保持在屏幕截图上。你知道我怎样才能避免这个问题吗?

【问题讨论】:

  • “当我更改viewController”是什么意思?正在某处进行一些编辑,你是否在这个之上展示了一些其他 UIViewController,或者是什么停止了动画?最好也包括代码
  • 对不起,不是很清楚......我的意思是例如当我更改标签时,或者当我进入另一个视图控制器时
  • 好的,所以当你将一个选项卡更改为另一个视图控制器时,动画会在更改时暂停,并且没有完成,这就是问题,对吧?
  • @KevinB 我假设如果您在 viewController 中的视图实例上制作动画,然后切换到另一个 viewController,您必须有一个新实例,因此您必须创建另一个动画。
  • @MilanNosáľ 不完全是,即使圆圈是 1.0,它也会停止在 1.3 比例(最大值)

标签: ios swift animation swift3 uiviewcontroller


【解决方案1】:

在 ViewDidAppear 上对 .identity 进行转换。类似于下面的代码:

class HomeController: UIViewController {

@IBOutlet weak var viewToAnimate: UIView!
override func viewDidLoad() {
    super.viewDidLoad()
}

override func viewWillAppear(_ animated: Bool) {
    self.viewToAnimate.transform = .identity
    animateView()
}

func animateView(){
    UIView.animate(withDuration: 1.0, delay: 0, options: [.repeat, .autoreverse], animations: {

        self.viewToAnimate.transform = CGAffineTransform(scaleX:
            1.3, y: 1.3)

    }, completion: nil)
}

}

您可能已经猜到的问题是 UIView.animate 仅在 ViewDidLoad 方法上调用,并且由于我们在从另一个返回此 ViewController 时无法访问该代码,因此最好在ViewWillAppear 方法。

如果在切换选项卡时出现同样的问题,请为您想要动画的视图创建一个单独的 UIView 子类,然后按以下步骤操作:

class AnimateView: UIView {

override func awakeFromNib() {
    super.awakeFromNib()
}

override func willMove(toWindow newWindow: UIWindow?) {
    super.willMove(toWindow: newWindow)
    self.transform = .identity
    animateView()
}

func animateView(){
    UIView.animate(withDuration: 1.0, delay: 0, options: [.repeat, .autoreverse], animations: {

        self.transform = CGAffineTransform(scaleX:
            1.3, y: 1.3)

    }, completion: nil)
}

}

在这里,您已经将动画功能带到了 UIView 对象中,每当视图出现时,动画就会被重置。

【讨论】:

    【解决方案2】:

    嗯,我还没有一个令人满意的答案(至少那会让我满意),但我想至少添加一些我能够通过一些实验获得的见解。

    首先,当viewController 不是当前呈现的动画时,动画似乎结束了。在您的情况下,这意味着动画停止并以状态结束,其中视图大 1.3 倍,并停止重复。 layoutSubviews 仅在您第一次展示时才会被调用。至少 viewController.viewDidLayoutSubviews 仅在开始时调用,而不是在您返回时调用(因此 layoutSubviews 在视图重新出现时不会被执行) - 因此动画不会重新启动。

    我尝试将动画移动到 UIViewControllerviewDidAppear - 这也不起作用,因为停止动画会导致视图已缩放 1.3 倍的状态。在创建动画之前将状态重置为 CGAffineTransform.identity 确实有效。

    现在,正如我所说,这可以作为一种解决方法,让您了解如何让它工作,但是,我认为您真正需要的是一些钩子,它可以告诉您的视图(而不是 viewController)它再次出现。但是下面这个最小的例子至少可以帮助其他人看一看,而不是从头开始。

    import UIKit
    import PlaygroundSupport
    
    class MyViewController : UIViewController {
    
        let animator = UIViewPropertyAnimator(duration: 1, timingParameters: UICubicTimingParameters(animationCurve: .linear))
    
        init(title: String) {
            super.init(nibName: nil, bundle: nil)
            self.title = title
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        let animatableView = UIView()
    
        override func loadView() {
            let view = UIView()
            view.backgroundColor = .white
    
            animatableView.frame = CGRect(x: 150, y: 400, width: 100, height: 100)
            animatableView.backgroundColor = UIColor.magenta
            view.addSubview(animatableView)
    
            self.view = view
        }
    
        override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
    
            self.animatableView.transform = CGAffineTransform.identity
            UIView.animate(withDuration: 1.0, delay: 0, options: [.repeat, .autoreverse], animations: {
                self.animatableView.transform = CGAffineTransform(scaleX:
                    1.3, y: 1.3)
            }, completion: nil)
        }
    
        override func viewDidLayoutSubviews() {
            super.viewDidLayoutSubviews()
            print("\(self.title) >> Lay out")
        }
    }
    
    let tabBar = UITabBarController()
    tabBar.viewControllers = [MyViewController(title: "first"), MyViewController(title: "second"), MyViewController(title: "third")]
    tabBar.selectedIndex = 0
    // Present the view controller in the Live View window
    PlaygroundPage.current.liveView = tabBar
    

    编辑

    我添加了几行代码来检查 self.animatableView.layer.animationKeys() 是否包含任何动画,似乎切换选项卡会从视图层移除动画 - 所以你必须找到一种方法在每次视图重新出现时添加动画。

    编辑 2 所以我会选择@SWAT 的答案并使用willMove(toWindow:) 而不是layoutSubviews

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-04-17
      • 1970-01-01
      • 1970-01-01
      • 2014-09-25
      • 1970-01-01
      • 2012-02-15
      • 2013-01-18
      • 1970-01-01
      相关资源
      最近更新 更多