Flutter Animation — Understanding the core of Staggered and Sequence Animation
By: Ken Lee Chiaw Huat
Tags: Flutter, Flutter Ui, Animation, Dart, Flutter Widget

Introduction

There are few main areas that I strongly believe as the key elements for any good mobile app design. The first would be the UI design, UX (user experience) and a good animation.

Since Flutter provides lots of out of the box widget that we can utilize and mix together for a good UI, most if not all, does not come with a good default animation.

Flutter team are fully aware of it and there has been lots of sharing from the team itself on the animation topic. This include ‘Widget of the Weeks’ series where the team behind Flutter created a very good video tutorial and sharing on the power of animation in Flutter and how to use it.

In this article, I will share my knowledge and the core basic specifically on staggered and multiple tweens animation. Why? Well most of the time, when we design any mobile app, we will need to implement multiple animation within the same screen and widget.

For example:

Introduction to Flutter Animations

Before we move into the details of it, is good to know that in Flutter, there are 2 techniques for animation:

Implicit Animation

Explicit Animation

Implicit Animations

Implicit animation is those widgets that come with pre-defined features/functionalities that are good enough for an animation. They extend ImplicitlyAnimatedWidget class.

For example, you can’t control the animation when to pause or reverse or doing multiple animation with different widget child groups together.

Example of implicit type of animation widgets are AnimatedContainer, AnimatedPositioned, AnimatedAlign and AnimatedOpacity.

So, if you want to have simple animation without the need to pause or reversing the animation, AnimatedFoo got you covered in which Foo is the name of the non-animated version of that widget.

For the complete list of implicitly animated widgets, go to here.

A simple AnimatedAlign widget

Another example of implicit animation: AnimatedContainer

But, to achieve the animation that contains multiple widgets that have different entry point within the same animating duration, the easiest approach is explicit animations.

Explicit Animations

In explicit animations, as you need to define the AnimationController, Animation and Tween objects, that means you have the full control of when an animation can be start and mixing multiple animation objects into 1 main staggered or sequence animation.

Animation

-> It is the core class of Flutter animation and it is an abstract class.

-> Since it is an abstract class, we can’t instantiate it for animation usage, but we can create one using AnimationController or Tweens.

-> Example:

Animation<double> — interpolates values between 2 decimal numbers over a given duration.

Animation<Color> — interpolates colors between two color values.

AnimationController

-> It controls the animation such as total animation duration, starting/stopping/reversing the animation and allowing anyone to know the status of the animation through listener.

-> It extends the abtract class Animation, which would mean all implemented methods in Animation class will be available in AnimationController.

-> Code Example:

-> Controller = AnimatioController(duration: Duration(miliseconds: 2800)).

Tweens

-> A tween allowed us to define how to interpolate between two values.

-> The interpolation is linear and not curve. Linear here means the animation from x to y will remain unchanged. To have a curvy type of animation, use CurvedAnimation

-> It is a stateless object that takes only begin and end value.

Now, with the above understanding, we can move on to the basic structure of staggered animation.

Let’s assume we want to create a something like this:

From the above picture, you will notice the following:

The animation started with the avatar picture been loaded from smaller to bigger size and at the same time opacity changed.

The divider below the avatar have its width size changed.

The bottom profile section (big blue section) having width enlarged, follow by opacity changed from 0 to 1.

Basically, there are multiple animation that occur together and some slightly later, in sequence. The complete list of animation in breakdown are as below:

The key steps to setup the animation in this sequence is:

Create an AnimationController that manages all of the Animations.

Create a Tween for each property being animated — Tween for the avatar opacity changes, Tween for avatar sizes changes, Tween for the divider and so on.

This is the main screen dart file.

Key info:

We need to create the AnimationController so that we can specify the total duration of the whole screen, we also need to provide the vsync. Thus, we need to implement SingleTickerProviderStatrMixin. What is vsync? Vsync basically helps in keeping track of the screen, so it won’t simply render the animation when the screen is not being displayed.

Take note, since we are creating an instance of AnimationController, thus we need to dispose it when the screen is not needed anymore during runtime. Therefore, this main class file is been created as Stateful type of widget.

As there is a lot of animations occurring, we can create a separate animator class that focus the animation part of the whole screen.

This is the StaggeredExampleAnimator class.

Here, we have the separated animator class and notice on the constructor in which we have can a reference of the AnimationController from the parent.

Also, we defined all the Animation objects that has its own animation rules such as opacity changes, size changes and width/height changes.

For example, the avatarOpacityAnimation is having the following code:

avatarOpacityAnimation = Tween(begin: 0.0, end: 1.0).animate(

CurvedAnimation(

parent: controller,

curve: Interval(0.1, 0.4, curve: Curves.ease)))

This mean, we are creating an animation object that will change its opacity from 0% to 100% and the animation will start at 0.1 seconds until 0.4 seconds. As I mentioned earlier, to have more control such as when the animation can begin and for how long, we must use Interval.

Tween (begin: 0.0, end: 1.0) — as the opacity min and max range is 0 to 1, thus this are the values.

This mean, we are creating an animation object that will change its opacity from 0% to 100% and the animation will start at 0.1 seconds until 0.4 seconds. As I mentioned earlier, to have more control such as when the animation can begin and for how long, we must use Interval.

Tween (begin: 0.0, end: 1.0) — as the opacity min and max range is 0 to 1, thus this are the values.

Interval (0.1, 0.4, curve: Curves.ease) — this would mean I want the opacity animation to start at the 0.1 interval, and end at 0.4 interval out of the total 1 and using the curve ease. There are others animation curves formula, visit here for the full list.

Lets take another example, the avatarSizeAnimation code:

avatarSizeAnimation = Tween(begin: 10.0, end: 80.0).animate(

CurvedAnimation(

parent: controller,

curve: Interval(0.1, 0.4, curve: Curves.ease)))

This mean, we are creating an animation object that will change its size from 10 pixels to 80 pixels and the animation will start at 0.1 seconds and end at 0.4 seconds. To control when the animation will start, using the interval will allow us to control the timing.

In the UI build code, this is how we link the widget to the animation. For example, the avatar widget where we want to control the opacity and the size during load time:

In the above code snippet, we used the Opacity widget to manage the opacity animation. As because I want to have some border decoration on my avatar picture, we can use the Container widget and mapped the decoration color to the same opacity animation object.

As for the avatar itself, there is a property called radius that we can used to control the radius size from small to big — and this is done by linking it to the size animation object we created above.

The result:

As for the rest of the section such as the divider animation and the bottom square animation is using the same concept that I shared above. As long we understand the purpose of the code for AnimationController, Animation and Tween, we have full control of what we can achieve in explicit animation for Flutter.

What if you want to have the same widget UI to have more than 2 animation at the same time? A sequence of animation on the same widget? For example, changing position from bottom left, then to top left, then to top right, and then bottom right before ending at bottom left again.

Introducing multiple tweens.

Tween Sequence / Sequence of Tweens

If you notice the above, the same widget moved from 1 position to a few more position before it is back again to the main point. Total points 5 points (including the starting point).

To achieve this, we will need to combine tweens in different intervals of the animation.

The TweenSequence class was created for this purpose, providing this functionality out of the box.

The TweenSequence works by providing a set of TweenSequenceItem which consist of a Tween and a weight. The weight will determine how much time each tween will be allowed to run during the duration of the animation.

The above example can be done by the following code:

Let’s break down the code.

The object wandering1CubeAlignmentAnimation is an Animation<Alignment> type of instance class. Why Alignment? Because we want to have the widget position to change and Alignment comes with helpful positioning such as Alignment.bottomLeft.

The TweenSequenceItem is basically an item which holds a tween and a weight. The weight here is all the same which is 1.0. You can specify the weight to be larger, smaller or same for all. The purpose of weight is basically to control which item (TweenSequenceItem) to have slightly longer playing animation.

The above code shows how the UI part is been done.

I hope you gain some useful info and have some fun following the example on staggered animation. With strong foundation, in this case of animation, it is important to understand the core and basic first before designing a real application.

Feel free to leave comments and feedback. The whole source codes are available here. Cheers.