---
title: "CAAnimations and groups"
slug: caanimations-and-groups
section: tech
date: 2018-11-08T19:49:00.000Z
canonical: https://roland.leth.ro/blog/tech/caanimations-and-groups
---

Everyone loves animations and I think every app should make use of them; with care, but that in a future post. The easiest way to add animations is with `UIView`’s `animate` method, or with `UIViewPropertyAnimator`s. Pretty straightforward and easy to use, but they don’t support animating `CALayer` properties, like `borderColor` or `borderWidth`. For these, we have `CABasicAnimation`, or rather all of its concrete subclasses: `CABasicAnimation`, `CAKeyframeAnimation`, `CAAnimationGroup`, or `CATransition`. In this post we’ll quickly cover `CABasicAnimation` and `CAAnimationGroup`.

Say we want to animate the `borderColor` of a view, this is how we’d go about it:

```swift
let borderColorAnimation = CABasicAnimation(keyPath: "borderColor") // 1
		
borderColorAnimation.duration = 0.15 // 2
borderColorAnimation.fromValue = UIColor.red.cgColor // 3
borderColorAnimation.toValue = UIColor.blue.cgColor // 4
borderColorAnimation.timingFunction = CAMediaTimingFunction(name: .linear) // 5
borderColorAnimation.beginTime = CACurrentMediaTime() + 0.2 // 6

view.layer.add(borderColorAnimation, forKey: "blueBorderColorAnimation") // 7
```

First, we initialize one with a `keyPath`, the property of the layer we want to animate (1). We then set some properties, like the duration (2), the starting (3) and end (4) colors, the timing function (5) and a start time (6).  Lastly, we have to add this animation to our layer under a `key`, which is just a string that identifies the animation.

The `fromValue` and `toValue` are of type `Any`, since they have to be able to accept pretty much anything, from `CGColor`s (our case), to `CGRect`s if we want to animate the `bounds`, or `Floats`, if we want to animate the `borderWidth` (like below).

The timing functions are the equivalent of the ones used on `UIView.animate`, `UIViewAnimationOption`s, `UIViewAnimationOptionCurveLinear` in our case.

The `CACurrentMediaTime()` gives us the current time, to which we add `0.2` seconds, since in our case, we want it to start with a slight delay.

Now, if we want to animate the `borderWidth` at the same time, we’d go about in a similar fashion:

```swift
let borderWidthAnimation = CABasicAnimation(keyPath: "borderWidth")
		
borderWidthAnimation.duration = 0.15
borderWidthAnimation.fromValue = 0.5
borderWidthAnimation.toValue = 1.5
borderWidthAnimation.timingFunction = CAMediaTimingFunction(name: .linear)
borderWidthAnimation.beginTime = CACurrentMediaTime() + 0.2

view.layer.add(borderWidthAnimation, forKey: "tripleBorderWidthAnimation")
```

The same properties are set, except the `fromValue` and `toValue`, which are now `Float`s. 

This already seems a bit wrong; we’re duplicating a lot of code, like the `duration`, `timingFunction` and the `beginTime`. Luckily for us, we can make use of `CAAnimationGroup`s. These allow multiple animations to be grouped and run together.

```swift
let borderColorAnimation = CABasicAnimation(keyPath: "borderColor") // 1
borderColorAnimation.fromValue = UIColor.red.cgColor
borderColorAnimation.toValue = UIColor.blue.cgColor

let borderWidthAnimation = CABasicAnimation(keyPath: "borderWidth") // 2
borderWidthAnimation.fromValue = 0.5
borderWidthAnimation.toValue = 1.5

let group = CAAnimationGroup() // 3
group.duration = 0.15
group.timingFunction = CAMediaTimingFunction(name: .linear)
group.beginTime = CACurrentMediaTime() + 0.2
group.animations = [borderColorAnimation, borderWidthAnimation] // 4

view.layer.add(group, forKey: "borderChangeAnimationGroup") // 5
```

We first create our `borderColor` (1) and `borderWidth` (2) animations as before, but we only set the `fromValue` and `toValue`. We then create a group (3), set the remaining properties on it — `duration`, `timingFunction`, `beginTime` — and also, a new one, called `animations`; here we set an array of `CAAnimation`s that we want to run concurrently in this group. Lastly, we add the group to the layer, just like we previously did with the individual `CABasicAnimation`s — the group is just a subclass of `CAAnimation`, remember.

This will run both animations at the same time, with the same time properties. It also allows us to write cleaner code that’s easier to reason with, but also less prone to errors, since everything is configured in one place. Imagine having 5 of these animations, then realizing that something is wrong — we’d have to change the values in all 5 places!

This was a very, very short introduction to `CAAnimation`. [Marin Todorov][1] wrote a _wonderful_ book about `CoreAnimation` which you can find [here][2]. I can’t recommend it enough, especially if you’re starting. 

Happy animating!

[1]:	https://twitter.com/icanzilb "Marin Todorov"
[2]:	https://store.raywenderlich.com/products/ios-animations-by-tutorials "iOS Animations by Tutorials"