denvdancsk
denvdancsk

Reputation: 3053

Prevent CAGradientLayer locations from returning to original values after using CABasicAnimation

I'm trying to make a gradient animate so that the locations of the two colors shift from left to right. The problems is that once the animation completes, the gradient locations snap back to their original position.

Here is my playground code:

import UIKit
import PlaygroundSupport

class MyViewController : UIViewController {

  let gradientLayer: CAGradientLayer = {
    let layer = CAGradientLayer()
    layer.colors = [ UIColor.red.cgColor, UIColor.blue.cgColor ]
    layer.locations = [0.0, 0.5]
    layer.startPoint = CGPoint(x: 0.0, y: 1.0)
    layer.endPoint = CGPoint(x: 1.0, y: 1.0)

    return layer
  }()

  override func viewDidLoad() {
    super.viewDidLoad()

    view.layer.addSublayer(gradientLayer)
    gradientLayer.frame = view.bounds

    let gradientChangeAnimation = CABasicAnimation(keyPath: "locations")
    gradientChangeAnimation.duration = 1
    gradientChangeAnimation.toValue = [0.5, 1.0]
    gradientLayer.add(gradientChangeAnimation, forKey: nil)

  }

  override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    gradientLayer.frame = view.frame
  }
}

// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()

How do I prevent the reset of the locations after the animation completes?

Upvotes: 0

Views: 603

Answers (1)

Brandon
Brandon

Reputation: 23485

You can just tell it to not remove on completion and set the locations to the new values:

override func viewDidLoad() {
    super.viewDidLoad()

    view.layer.addSublayer(gradientLayer)
    gradientLayer.frame = view.bounds

    CATransaction.begin()
    CATransaction. setCompletionBlock {
        gradientLayer.locations = [0.5, 1.0]
        gradientLayer.removeAllAnimations()
    }

    let gradientChangeAnimation = CABasicAnimation(keyPath: "locations")
    gradientChangeAnimation.duration = 1
    gradientChangeAnimation.toValue = [0.5, 1.0]
    gradientLayer.add(gradientChangeAnimation, forKey: nil)

    CATransaction.commit()
}

or set the fillMode and isRemovedOnCompletion properties appropriately.

override func viewDidLoad() {
    super.viewDidLoad()

    view.layer.addSublayer(gradientLayer)
    gradientLayer.frame = view.bounds

    let gradientChangeAnimation = CABasicAnimation(keyPath: "locations")
    gradientChangeAnimation.duration = 1
    gradientChangeAnimation.toValue = [0.5, 1.0]
    gradientChangeAnimation.fillMode = kCAFillModeForwards
    gradientChangeAnimation.isRemovedOnCompletion = false
    gradientLayer.add(gradientChangeAnimation, forKey: nil)
}

Upvotes: 1

Related Questions