DrPatience
DrPatience

Reputation: 1776

Animate CAGradientLayer in Swift

I am attemping to animate the CAGradientLayer using Swift. For a resource I'm using this post

Here is my code

class ViewController: UIViewController {

  var gradient : CAGradientLayer?;

  override func viewDidLoad() {
    super.viewDidLoad()
  }

  override func viewDidAppear(animated: Bool) {

    self.gradient = CAGradientLayer()
    self.gradient?.frame = self.view.bounds
    self.gradient?.colors = [ UIColor.redColor().CGColor, UIColor.redColor().CGColor]
    self.view.layer.insertSublayer(self.gradient, atIndex: 0)

    animateLayer()
  }

  func animateLayer(){

    var fromColors = self.gradient?.colors
    var toColors: [AnyObject] = [ UIColor.blueColor().CGColor, UIColor.blueColor().CGColor]

    var animation : CABasicAnimation = CABasicAnimation(keyPath: "colors")

    animation.fromValue = fromColors
    animation.toValue = toColors
    animation.duration = 3.00
    animation.removedOnCompletion = true
    animation.fillMode = kCAFillModeForwards
    animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
    animation.delegate = self

    self.gradient?.addAnimation(animation, forKey:"animateGradient")
  }
}

I've attempted this in Objective-C and it works, but I need to use it in Swift and when I run the program it animates but goes back to the previous color at the end, I need it so remain blue.

Upvotes: 23

Views: 17450

Answers (4)

Echelon
Echelon

Reputation: 7922

For those in the comments asking about endless animations, here's my stock sample code for an endlessly animated background:-

The full discussion and results can be seen on my blog

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // create the gradient layer
        let gradient = CAGradientLayer()
        gradient.frame = self.view.bounds
        gradient.startPoint = CGPoint(x:0.0, y:0.5)
        gradient.endPoint = CGPoint(x:1.0, y:0.5)
        gradient.colors = [UIColor.red.cgColor, UIColor.green.cgColor]
        gradient.locations =  [-0.5, 1.5]

        let animation = CABasicAnimation(keyPath: "colors")
        animation.fromValue = [UIColor.red.cgColor, UIColor.green.cgColor]
        animation.toValue = [UIColor.green.cgColor, UIColor.red.cgColor]
        animation.duration = 5.0
        animation.autoreverses = true
        animation.repeatCount = Float.infinity

        // add the animation to the gradient
        gradient.add(animation, forKey: nil)

        // add the gradient to the view
        self.view.layer.addSublayer(gradient)
    }
 }

Upvotes: 6

Alaeddine
Alaeddine

Reputation: 6212

I've attempted this in Objective-C and it works, but I need to use it in Swift and when I run the program it animates but goes back to the previous color at the end, I need it so remain blue.

You need just :

animation.removedOnCompletion = false // not true like in your code

Upvotes: 1

user2152001
user2152001

Reputation: 11

For future reference... The 100% CPU usage is caused by the animationDidStop function. It restarts the animation while the current animations isn't finished. Please check the finished flag:

override func animationDidStop(anim: CAAnimation, finished: Bool) {
    if finished {
        self.toColors = self.fromColors;
        self.fromColors = self.gradient?.colors

        animateLayer()
    }
}

Upvotes: 1

TheTiger
TheTiger

Reputation: 13364

I have checked your code and found one mistake here. You forgot to set color of self.gradient you are just giving colors to animation thats why animation is working fine and at the end you see its color goes back to red.

Write this missing code:

var toColors: [AnyObject] = [UIColor.blueColor().CGColor, UIColor.blueColor().CGColor]
self.gradient.colors = toColors // You missed this line
var animation : CABasicAnimation = CABasicAnimation(keyPath: "colors")

You can also check working code here: Sample

UPDATE: how do I repeat this gradient transition continuously ?

So you can use delegate of CAAnimation. It will let you know once the animation has been finished and then you can set the fromColors and toColors value and call the animateLayer() function again and again. But for this you will have to make few changes in your code.

  • Make fromColors and toColors global.
  • Change their value in animationDidStop delegate method.
  • Call the animateLayer() function again.

Here is the delegate method body:

override func animationDidStop(anim: CAAnimation!, finished flag: Bool) {

    self.toColors = self.fromColors;
    self.fromColors = self.gradient?.colors
    animateLayer()
}

And you can also check working code here: Sample

Upvotes: 32

Related Questions