使用偏移量启动 CABasicAnimation

Start CABasicAnimation with an offset

我很难理解 CABasicAnimation 的计时系统,尤其是 beginTimetimeOffset 属性。我经历了 this tutorial and questions such as this one,它们都解释了 pausing/resuming 动画的一种方式。尽管如此,我仍然无法弄清楚如何 直接使用偏移 启动动画。

例如,我想在 2.0 秒开始我的动画,这意味着如果我的动画是从白色到黑色的颜色过渡,持续时间为 3.0 秒,那么动画将从深灰色开始并过渡在 1.0 秒内变黑。

我不能使用 UIViewPropertyAnimator,因为我的动画是关于改变渐变的颜色 (CAGradientLayer)。

当我将动画添加到图层时,如何以我想要的偏移开始我的动画?

要直接使用偏移量启动 CABasicAnimation,只需将其 timeOffset 设置为动画时间轴内您希望它开始的时间即可。

因此,例如,如果您的动画 duration 设置为 3,而 timeOffset 设置为 2,则动画将(明显地)在动画的 2 秒处开始。

但是,这不会阻止动画然后回绕以完成被跳过的动画部分(从 0-2 秒)。如果你想让动画在到达它的 toValue 后停止,你可以将 repeatDuration 设置为 1 以在 1 秒后切断动画。

这是一个完整的 Playground 示例,您可以在其中尝试动画属性并单击实时视图以查看动画:

import UIKit
import PlaygroundSupport

class GradientView: UIView {
    override class var layerClass: AnyClass {
        CAGradientLayer.self
    }

    override var layer: CAGradientLayer {
        super.layer as! CAGradientLayer
    }

    override init(frame: CGRect) {
        super.init(frame: frame)

        layer.colors = [UIColor.white.cgColor, UIColor.white.cgColor]
        layer.locations = [0, 1]

        let tap = UITapGestureRecognizer(target: self,
                                         action: #selector(animateGradient))
        addGestureRecognizer(tap)
    }

    required init?(coder: NSCoder) {
        fatalError("Not implemented")
    }

    @objc func animateGradient() {

        // Animate the `colors` property of the gradient layer.
        // In this example we're just animating the first color of
        // a two-color gradient.
        let anim = CABasicAnimation(keyPath: "colors")
        anim.fromValue = [UIColor.white.cgColor, UIColor.white.cgColor]
        anim.toValue = [UIColor.black.cgColor, UIColor.white.cgColor]

        // Sets the length of the animation's timeline.
        //
        // Note that in this case, this is not the _effective_ duration
        // as we are stopping the animation after 1 second due to setting
        // `repeatDuration` below.
        anim.duration = 3

        // Where in the animation's timeline the animation should
        // effectively start.
        //
        // In this case, this starts the animation 2 seconds in to the
        // timeline, which makes it look like the first gradient color
        // immediately starts at dark gray.
        anim.timeOffset = 2

        // Stops the animation when it gets to the `toValue`.
        // This makes the effective duration 1 second long.
        //
        // Comment this out to let the animation loop back around
        // so that it then fades from white to dark gray, if desired.
        anim.repeatDuration = anim.duration - anim.timeOffset

        layer.add(anim, forKey: nil)
    }
}

let gradientViewFrame = CGRect(x: 0, y: 0, width: 200, height: 200)
PlaygroundPage.current.liveView = GradientView(frame: gradientViewFrame)