Search code examples
ioscore-animationcalayercabasicanimation

CoreAnimation — Layer flickers to final value before animation starts?


I'm attempting to do a simple CABasicAnimation of a layer's background color from red to blue.

After adding the animation and setting the model layer's final value, the animations flickers to blue before turning red again, and animating to blue.

My code is:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    // Create red layer and add to view
    let redLayer = CALayer()
    redLayer.backgroundColor = UIColor.red.cgColor
    redLayer.position = view.center
    redLayer.bounds.size = CGSize(width: 100, height: 100)
    view.layer.addSublayer(redLayer)

    DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) {

        // After a 1 second delay, animate from red to blue.

        let anim = CABasicAnimation(keyPath: "backgroundColor")
        anim.duration = 3
        anim.fromValue = redLayer.backgroundColor
        anim.toValue = UIColor.blue.cgColor
        redLayer.add(anim, forKey: "")

        // Set background color to final value
        redLayer.backgroundColor = UIColor.blue.cgColor
    }
}

What's happening here?

enter image description here


Solution

  • The short-ish answer is that you are getting an implicit animation when you update an implicitly animatable property of a layer (backgroundColor in this case).

    This 0.25 second animation is taking precedence over your explicit animation because it is added afterwards. This implicit animation happens because the layer is "standalone" (that is; it's not owned by a view).

    To get rid of this implicit animation you can create a CATransaction and disable actions for only the scope that updates the layer's property:

    CATransaction.begin()
    CATransaction.setDisableActions(true)
    
    redLayer.backgroundColor = UIColor.blue.cgColor
    
    CATransaction.commit()
    

    As an alternative to disabling the implicit animation you can also update the layer before adding the explicit animation. I have a rather detailed explanation of the implications of updating the layer before or after adding the animation in this answer if you want to learn more about this.