为啥在添加视图后立即启动 UIView 动画不起作用?

Posted

技术标签:

【中文标题】为啥在添加视图后立即启动 UIView 动画不起作用?【英文标题】:Why is UIView animation not working when starting right after view is added?为什么在添加视图后立即启动 UIView 动画不起作用? 【发布时间】:2017-07-01 22:45:39 【问题描述】:

UIView 的动画应该在视图添加到父视图后立即开始:

class myView: UIView 
    override func didMoveToSuperview() 
        super.didMoveToSuperview()

        UIView.animate(
            withDuration: duration,
            delay: 0,
            options: .curveLinear,
            animations: 
                CATransaction.begin()
                CATransaction.setAnimationDuration(duration)
                self.layer.colors = [color1, color2]
                CATransaction.commit()
        ,
            completion: nil
        )
    

但是,结果是当视图在父视图中可见时动画已经结束。 UIView.animate 没有动画,而是立即设置self.layer.colors,可能是因为调用didMoveToSuperview 时视图还不可见。

如何让动画正常启动?

【问题讨论】:

在视图控制器的生命周期中,您的 MyView 实例添加到视图层次结构中的哪个位置? @thefredelement 覆盖两个绘图函数都没有帮助,结果相同。 @beyowulf 在super.viewDidAppear(animated) 之后。 您是否要为CAGradientLayer 制作动画? @beyowulf 是的.. 【参考方案1】:

可以通过创建CABasicAnimation 并将其添加到您的CAGradientLayer 来使用核心动画制作渐变动画。您不需要将其包装在 UIView 动画块中,并且可以从 viewDidMoveToSuperview 执行此操作,前提是您在将根视图添加到 @987654326 之后的某个时间将 UIView 子类实例添加到视图层次结构中@。例如,在操场上可以写:

import UIKit
import PlaygroundSupport

class MyView: UIView

    var duration = 20.0

    var fromColors = [UIColor.orange.cgColor, UIColor.blue.cgColor]
    var toColors = [UIColor.red.cgColor, UIColor.green.cgColor]

    override func didMoveToSuperview() 
        super.didMoveToSuperview()

        let gradientLayer = CAGradientLayer()
        gradientLayer.frame = bounds
        layer.addSublayer(gradientLayer)

        let animation = CABasicAnimation(keyPath: "colors")
        animation.fromValue = fromColors
        animation.toValue = toColors
        animation.duration = duration
        gradientLayer.add(animation, forKey: nil)

        gradientLayer.colors = toColors
    


class ViewController: UIViewController

    override func viewDidAppear(_ animated: Bool) 
        super.viewDidAppear(animated)
        let myView = MyView(frame: view.bounds)
        view.addSubview(myView)
    


PlaygroundPage.current.liveView = ViewController()

并看到一个 20 秒的动画,从垂直的橙色到蓝色渐变动画到垂直的红色到绿色渐变。

【讨论】:

谢谢,现在可以正常使用了。唯一需要改变的是在添加动画gradientLayer.add(animation, forKey: nil)之前应该设置最终状态gradientLayer.colors = toColors。否则在做连续动画时有时会闪烁。甚至不再需要在didMoveToSuperview 中启动动画,它也可以在init 函数中使用。

以上是关于为啥在添加视图后立即启动 UIView 动画不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

UIView.animate 不在一个功能上制作动画

如何中断 UIView 动画

UIView animateKeyframes 不起作用

当我将 UIView 动画放在不同类的 containerView 中时,为啥我的 UIView 动画不起作用?

removeAllAnimations 不起作用后添加动画

UIView 块动画不起作用