Aodh
Aodh

Reputation: 682

CAKeyframeAnimation with staggered begin time

I'm trying to create an animation where items come in to view staggered in time. To this end I used a CAKeyframeAnimation but to achieve the staggering I need to specify a beginTime.

The problem is that I'd also like the animation not to snap back to the original position when it completes so I specify the value on the model as follows: view.layer.transform = CATransform3DIdentity before the animation is added to the layer.

The animation does, however, snap back to the initial position because I've specified a beginTime. Is there a way around this?

func addAnimation(view: UIView, index: Int) {
    let values = RK4SpringAnimation(tension: 600, friction: 60, initialVelocity: 0) // just provides an array of values between 0.0 and 1.0.
    let positions = values.map { Float(view.layer.frame.width) - (Float($0) * Float(view.layer.frame.width)) }
    let animation = CAKeyframeAnimation(keyPath: "transform.translation.x")
    animation.values = positions
    animation.duration = 0.716
    animation.beginTime = CACurrentMediaTime() + Double(index) * 0.015
    view.layer.transform = CATransform3DIdentity // set the final value on the model.
    view.layer.add(animation, forKey: "transform2")
}

Upvotes: 0

Views: 440

Answers (2)

rob mayoff
rob mayoff

Reputation: 385600

After you add the animation, you should set the property value to the final value of the animation. Is the final value CATransform3DIdentity?

If the animation's beginTime is in the future, and the animation's begin value is not equal to its end value, then you can set animation.fillMode = .backwards to tell Core Animation to apply the animation's begin value to the layer until beginTime is reached.

func addAnimation(view: UIView, index: Int, show: Bool) {
    let values = RK4SpringAnimation(tension: 600, friction: 60, initialVelocity: 0) // just provides an array of values between 0.0 and 1.0.
    let positions = values.map { Float(view.layer.frame.width) - (Float($0) * Float(view.layer.frame.width)) }
    let animation = CAKeyframeAnimation(keyPath: "transform.translation.x")
    animation.values = positions
    animation.duration = 0.716
    animation.beginTime = CACurrentMediaTime() + Double(index) * 0.015
    animation.fillMode = .backwards
    view.layer.add(animation, forKey: animation.keyPath)
    view.layer.setValue(positions.last!, forKey: animation.keyPath!)
}

Upvotes: 2

Rainer Schwarz
Rainer Schwarz

Reputation: 380

One way I used to solve this problem is to set a CAAnimationDelegate for your animations and implement animationDidStop(CAAnimation, finished: Bool). Create a reference to your view's layer and set the desired transformation when the animation has finished.

Upvotes: 1

Related Questions