Animated gradient layers in Swift

Prabhu S
3 min readJul 9, 2019

In this blog post, we will look at how to use the CAGradientLayer API and create some cool animated gradient effects like the ones seen in apps like Instagram.

CAGradientLayer

The CAGradientLayer is a CALayer that allows us to draw gradients. It can accept any number of colors as input and blend those colors together to render a continuous gradient of colors.

let gradient = CAGradientLayer()
gradient.frame = self.view.bounds
gradient.colors = [
UIColor(red: 48/255, green: 62/255, blue: 103/255, alpha: 1).cgColor,
UIColor(red: 244/255, green: 88/255, blue: 53/255, alpha: 1).cgColor
]
gradient.startPoint = CGPoint(x:0, y:0)
gradient.endPoint = CGPoint(x:1, y:1)
self.view.layer.addSublayer(gradient)

The code above creates a diagonal gradient between two colors. The direction of the gradient can be controlled by the adjusting the start and end points of the gradient.

Animating Gradients

Since all CALayer proporties are animatable we can create a CABasicAnimation on the colors property of the CAGradientLayer to show a smooth transition from one gradient to another.

let gradientChangeAnimation = CABasicAnimation(keyPath: "colors")
gradientChangeAnimation.duration = 5.0
gradientChangeAnimation.toValue = [
UIColor(red: 244/255, green: 88/255, blue: 53/255, alpha: 1).cgColor,
UIColor(red: 196/255, green: 70/255, blue: 107/255, alpha: 1).cgColor
]
gradientChangeAnimation.fillMode = kCAFillModeForwards
gradientChangeAnimation.isRemovedOnCompletion = false
gradient.add(gradientChangeAnimation, forKey: "colorChange")

Continuous Animations

We can expand on this approach and create a continuous looping animation where one gradient seamlessly blends into another over time. To implment a continuous gradient we must extend our view controller to conform to the CAAnimationDelegate protocol. An example of such an implementation is shown here.

class ViewController: UIViewController {

let gradient = CAGradientLayer()
var gradientSet = [[CGColor]]()
var currentGradient: Int = 0

let gradientOne = UIColor(red: 48/255, green: 62/255, blue: 103/255, alpha: 1).cgColor
let gradientTwo = UIColor(red: 244/255, green: 88/255, blue: 53/255, alpha: 1).cgColor
let gradientThree = UIColor(red: 196/255, green: 70/255, blue: 107/255, alpha: 1).cgColor

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}

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

gradientSet.append([gradientOne, gradientTwo])
gradientSet.append([gradientTwo, gradientThree])
gradientSet.append([gradientThree, gradientOne])


gradient.frame = self.view.bounds
gradient.colors = gradientSet[currentGradient]
gradient.startPoint = CGPoint(x:0, y:0)
gradient.endPoint = CGPoint(x:1, y:1)
gradient.drawsAsynchronously = true
self.view.layer.addSublayer(gradient)

animateGradient()

}

func animateGradient() {
if currentGradient < gradientSet.count - 1 {
currentGradient += 1
} else {
currentGradient = 0
}

let gradientChangeAnimation = CABasicAnimation(keyPath: "colors")
gradientChangeAnimation.duration = 5.0
gradientChangeAnimation.toValue = gradientSet[currentGradient]
gradientChangeAnimation.fillMode = kCAFillModeForwards
gradientChangeAnimation.isRemovedOnCompletion = false
gradient.add(gradientChangeAnimation, forKey: "colorChange")
}

}

extension ViewController: CAAnimationDelegate {
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
if flag {
gradient.colors = gradientSet[currentGradient]
animateGradient()
}
}
}

In the code above we start off by creating 3 different gradients. We the append them in an array called gradientSet, out animation will loop through the array and blend one gradient into another. We keep a simple index currentGradient to keep track of which gradient is to be displayed and change the toValue of our gradientAnimation to that particular gradient. Since we’re going to be rerendering our gradientlayer we set the drawAsynchronously flag to true.

Conclusion

CAGradientLayer is a powerful API and can be used in conjuntion with other CALayer APIs provided by iOS to create some really cool effects in a very simple concise manner.

--

--

Prabhu S

Mobile App Dev, Augmented Reality Enthusiast, Graduate Student @ Carnegie Mellon University