SwiftUI animation sequence

Cristhian Leon
Apr 17 · 4 min read
Photo by Jeffrey Brandjes on Unsplash

Having done a few animations with SwiftUI, I have realized how tough it is to use the withAnimation() modifier on multiple properties and views at different times or sequentially. Besides, when it comes to moving views around in a very particular way withAnimation() may lack clarity, extensibility, and sometimes organization. That’s why I’m going to show you the AnimationSequence framework I’ve written that wraps the beauty of SwiftUI.Animation and declutters our code a bit. Let’s dive into it.

This is what I normally find when looking for tutorials on Google or YouTube on how to animate views sequentially. I’ll be explaining what is going on within this snippet, but first, let’s check it out, shall we?

First approach when it comes to a sequence of animations.

Ok, what do we have here? let’s see what’s happening with this code, why it can be painful and expensive when it comes to updates or extensions. The code snippet is:

  • keeping track of booleans that tell when a view is being animated.
  • using separate booleans for each view that we want to animate differently (or in a different moment).
  • using booleans for different properties we want to animate.
  • using boolean in a ternary operator to set a different value depending on whether it’s on or off.
  • and delaying animations based on the previous durations.

Imagine that now, we need to change any animation duration, or we want to move some views horizontally instead of vertically, or we’d like to add a delay to one of the animations, or just as simple as grouping animations together. Even though the approach suggested by the code above is not bad for smaller examples, it is going to cost a lot of refactoring and probably a headache while dealing with more complex scenarios.

To get our terrain ready, let’s first add an animation state where we keep track of everything that’s happening to our views, such as colors, offsets, positions, borders, scales, etc. In this step, we’ll clean up the ContentView and have more flexibility on which value to set for each specific property. A little disclaimer before we move forward: This is my approach to solving this problem, and it is far from being perfect or the best solution, it’s just what I’ve found more fun to work with.

Introduce AnimationState to make our View cleaner.

As we can see in the above snippet, introducing the AnimationState removes lots of smells and makes our View looks cleaner, however, animating the views is still a fairly large amount of work, keeping track of animation durations and deciding the order of those animations, I am confident to say it is a painful task, considering this animation only consists in moving three circles up and down and then change their color.

After this huge introduction to the problem, to the current situation, and cleaning up the stage a little, let’s talk about what brings us to this article — how to write a nice animation sequence without caring too much about delays, animation order, or crazy details other than the actual animation definitions, such as — move this view up by 20 pixels, change the background color of this view, increase the scale of this other view to 2, etc.
Said that we can picture a non-existent animation sequence code(because we haven’t written it) that looks clean and handy — of course, imaginary code within the Swift syntax and what is humanly possible.

An interesting expectation syntax of AnimationSequence.

There is a couple of things we can highlight from this imaginary snippet:

  • The code looks cleaner than before since we got rid of unnecessary calculations of delays.
  • We set a default duration to 0.5 and easing to .default for all of our concatenated animations. // 1.
  • We give specific animation values to every block we append to the sequence. // 2.
  • To finish our sequence definition and start animating, we call the function start() on it.

As you might have imagined already, we require AnimationSequence to follow a builder pattern in which it returns itself every time we call the function append. It should also receive the optional values duration, delay, easing, and a non-optional trailing closure with the block of code that we want to execute later within the actual withAnimation() block. Let’s see the builder.

Bare-bones AnimationSequence builder.

To save all animation values, let me introduce to you the AnimationConfig structure that holds duration, delay, easing, and a block/closure.

AnimationConfig struct to store the animation behavior.

Now, we are ready to write the start() function. Based on all the animations we’ve appended, it creates a sequence by dispatching every animation with a time offset, which means, that the duration of the previous one is the delay of the current same process for every animation we have. For instance, let’s say we have an initial timeOffset=0 and when the first animation A comes, timeOffset increases its value by A.duration + A.delay, hence dispatching the next animation B timeOffset seconds later.

the core function where all AnimationSequence magic happens.

After a decent amount of time reading code (if you didn’t skip it), I hand to you the whole implementation of AnimationSequence, it’s not much different from the snippets we’ve seen so far, it’s just a more complete piece of code, I’ve added some debug flags, asynchronous tasks, an onFinish callback, I split the code into some files and did some cleaning up in general.

Thanks so much for reading. I hope you have enjoyed this small piece of code, and if it was useful for you, don’t be shy to 👏 on this article or just leave me a comment telling me how you liked it. See you next time.

Nerd For Tech

From Confusion to Clarification

Nerd For Tech

NFT is an Educational Media House. Our mission is to bring the invaluable knowledge and experiences of experts from all over the world to the novice. To stay up to date on other topics, follow us on LinkedIn. https://www.linkedin.com/company/nerdfortech

Cristhian Leon

Written by

Curious, passionate iOS Developer, interested in ML, and clean code principles.

Nerd For Tech

NFT is an Educational Media House. Our mission is to bring the invaluable knowledge and experiences of experts from all over the world to the novice. To stay up to date on other topics, follow us on LinkedIn. https://www.linkedin.com/company/nerdfortech

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store