Sam Fischer
Sam Fischer

Reputation: 1472

CAGradientLayer color change animation not executing

I'm trying to get a very basic CAGradientLayer animation to work. I have a basic 2 color CAGradientLayer set up and added to my UIViewController.

// Set up the gradient layer.
var gradientLayer: CAGradientLayer! {
    let layer = CAGradientLayer()
    layer.frame = self.view.bounds
    layer.colors = [UIColor.redColor().CGColor, UIColor.yellowColor().CGColor]
    layer.locations = [0.0, 1.0]
    return layer
}

I am trying to animate it with the following code:

@IBAction func changeBackground(sender: AnyObject) {
    let oldColors = self.gradientLayer.colors
    let newColors = [UIColor.purpleColor().CGColor, UIColor.blueColor().CGColor]
    self.gradientLayer.colors = newColors
    let animation: CABasicAnimation = CABasicAnimation(keyPath: "colors")

    animation.fromValue = oldColors
    animation.toValue = newColors
    animation.duration = 0.3
    animation.removedOnCompletion = true
    animation.fillMode = kCAFillModeForwards
    animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
    animation.delegate = self

    self.gradientLayer.addAnimation(animation, forKey: "animateGradientColorChange")
}

However, this code does not yield any change in the CAGradientLayer. What am I doing wrong here ?

Upvotes: 3

Views: 981

Answers (1)

Losiowaty
Losiowaty

Reputation: 8006

You are returning a new layer object every time from your gradientLayer property. You need to change it a bit, so that it is lazily initiated :

lazy var gradientLayer: CAGradientLayer! = {
    let layer = CAGradientLayer()
    layer.frame = self.view.bounds
    layer.colors = [UIColor.redColor().CGColor, UIColor.yellowColor().CGColor]
    layer.locations = [0.0, 1.0]
    return layer
}()

For completeness sake, what you had originally was a computed property, which meant that the code was executed each time you accessed it. With lazy properties, the code is executed only once, when the property is first accessed, and then the same object is returned.

The difference can be observed with this playground :

//: Playground - noun: a place where people can play

import UIKit

struct Dummy {

    var gradientLayer: CAGradientLayer! {
        let layer = CAGradientLayer()
        layer.colors = [UIColor.redColor().CGColor, UIColor.yellowColor().CGColor]
        layer.locations = [0.0, 1.0]
        return layer
    }

    lazy var lazyGradientLayer: CAGradientLayer! = {
        let layer = CAGradientLayer()
        layer.colors = [UIColor.redColor().CGColor, UIColor.yellowColor().CGColor]
        layer.locations = [0.0, 1.0]
        return layer
    }()
}

var dummy = Dummy()

let l1 = dummy.gradientLayer
let l2 = dummy.gradientLayer

let lazy1 = dummy.lazyGradientLayer
let lazy2 = dummy.lazyGradientLayer

Upvotes: 4

Related Questions