Chain Animations in Swift
One animation after another
Anyone who has use animations in Swift will have become (possibly unwillingly) familar with an animation pyramid. Look further for both an example of this, and how you can avoid being another pyramid victim.
Difficulty: Beginner | Easy | Normal | Challenging
- You can use a Single View Application or Playgrounds application showing the view controller. In either case Auto Layout is a big part of this. Tutorials? Playgrounds with the UI and Single View Application and Auto Layout.
UIView: An object that manages the content for a rectangular area on the screen
You might well have dabbled with animations in Swift. Good for you! They are fun, and we can see a problem developing if we start to chain animations using
it’s a mess! This could be a pyramid of DOOM.
This isn’t a fully working example, so this article will take us through a simple animation and how it might be coded using the best that
UIKit has to offer us.
Are you ready? Let us get started!
Let’s see an animation of a rectangle coming onto the screen, rotating and zooming and then then making a swift exit off the side of the screen. Something a little like the following:
This is possible by using the following code that I whacked into
func viewDidAppear(_ animated: Bool):
Which, as you can see has three calls to
class func animate(withDuration duration: TimeInterval, animations: @escaping () -> Void, completion: ((Bool) -> Void)? = nil) which means we have a great solution that:
- isn’t easy to read
- is difficult to maintain
- that I’m not really sure what is going to happen when reading the code
I’ve made a Gist with the full view controller class to help you
There must be a better way.
Step in the animateKeyframes
The method creates an animation block to be used in keyframe animations. The class signature is slightly intimidating, an man there are a large number of
UIView.KeyframeAnimationOptions within that.
Let us look at the solution before we dive in:
This works functionally exactly the same as the animate method shown at the top of this article.
It does so with the (initial) parameters for animatKeyFrames:
withDuration: The duration for the animation
delay: The wait time before the animation starts
options: A set of options that can be picked. Choice picks are
.autoreverse (which has to be used with
.allowUserInteraction (Apple have a full list of these)
animations: The animations using
Keyframe(withRelativeStartTime:relativeDuration:animations:). More on that in a minute.
completion: Not shown here, but an optional completion block
Remember when I said we’d come back to
Keyframe(withRelativeStartTime:relativeDuration:animations:)? This is that time.
has the following parameters:
frameStartTime: A relative value between 0 and 1. In the example above I’ve equally spaced the times apart by using 0, 0.33 and 0.66 — and the first of those will start immediately.
frameDuration: The relative duration, so in my example I set each key frame to have a duration of 0.25
animations: The block containing the animations; that is in order the appearance, transform and scale followed by the exit.
Did you know
You can overlap the keyframes! There’s nothing wrong with that, and you can certainly make a number of fun effects doing so! Awesome!
So keyframes allow you flexibility, and avoid that rather nasty nested set of blocks. However, you may still have to use
UIView.animate. You can’t win them all.
We’ve all used completion handlers to manage the flow of data within our App. This is usually a great solution, and certainly won’t cause you irretrievable issues in your App. However, the programmers pyramid of doom makes code difficult to maintain and add features to in the future?
The solution — animateKeyframes — will help you create applications that will pass your code reviews and enable you to produce quality code.
Isn’t that what we are all here for?
If you want to get in touch, hit me up on Twitter.