Flutter Animations Comprehensive Guide

Roaa Khaddam
Flutter Community
Published in
11 min readApr 24, 2022

In this article, I will do my best to cover, in great detail and with multiple examples, everything you need to know about Flutter animations. By the end of this article you’ll be able to add animations to your Flutter app with a wide range of complexity. And you’ll know which of the various approaches available in Flutter is best suited for your animation goals. So let’s get right to it!

Index:

TL;DR

You can see and tinker with the code of all the animations in this tutorial in this DartPad.

Also, I recently shared a Twitter thread that is basically a summary of this tutorial, so you can check it out.

Introduction

At the most basic level, animations in a Flutter app can be seen as one of two types: drawing-based, and code-based animations. Drawing-based animations are animated graphics, vectors, characters, or anything that is “drawn” then animated. On the other hand, code-based animations are focused on widget layouts and styles (lists, colors, text, ..etc). We’ll talk about drawing-based briefly at the end of this article, but because they’re usually achieved using 3rd party frameworks/packages, we will focus more on code-based animations. This is not to say code-based animations are limited, but on the contrary, Flutter animations allow you to create absolutely stunning, creative, and pretty complex animations without the need for 3rd party packages!

Code-based animations in Flutter have 2 types: Implicit animations & Explicit animations. In each of these types, you can either use ready-to-use widgets, or create your own widgets. Let’s dive deeper into each type with some examples.

1. Implicit Animations

Back to top 👆🏼

These are the simplest animations and easiest to use. Changing a value is enough to trigger an animation and Flutter handles everything behind the scenes.

1.1 Implicit Animations with Ready-to-use widgets

They’re called AnimatedFoo widgets, where Foo is the animated property. Most of them are animated versions of the widgets you already know and use, like Container/AnimatedContainer, Padding/AnimatedPadding, Positioned/AnimatedPositioned, …etc.

For example, check out this animation:

Flutter Implicit Animation Example with AnimatedFoo Widgets

This animation was achieved using only AnimatedContainer, AnimatedPositioned, and AnimatedDefaultTextStyle widgets. Just give them a duration value and a changing variable, and you’re good to go!

AnimatedPositioned(
top: selectedItemIndex * itemHeight,
left: 0,
right: 0,
duration: const Duration(milliseconds: 200),
curve: Curves.easeInOut,
child: //...
),
//...AnimatedContainer(
duration: const Duration(milliseconds: 200),
curve: Curves.easeInOut,
decoration: BoxDecoration(
color: selectedItemIndex == i ? yellow : pink,
border: Border.all(
color: selectedItemIndex == i
? Colors.white
: Colors.transparent,

width: 2,
),
),
child: AnimatedDefaultTextStyle(
duration: const Duration(milliseconds: 200),
style: TextStyle(
color: selectedItemIndex == i
? Colors.black
: Colors.white,

),
child: const Text('Featured!'),
),
),

And simply each list item is wrapped with an InkWell widget with the following onTap method:

onTap: () => setState(() => selectedItemIndex = i),

And this is enough to trigger the animation!

You can view the full code of this animation as well as all the others in this tutorial in this DartPad. So in this article I’m going to highlight only the parts of the code that were directly responsible for the animation.

Here’s a full list of available AnimatedFoo widgets

AnimatedAlign

AnimatedContainer

AnimatedDefaultTextStyle

AnimatedOpacity

AnimatedPadding

AnimatedPhysicalModel

AnimatedPositioned

AnimatedPositionDirectional

AnimatedSize

So we have AnimatedFoo widgets for properties like opacity, padding, align, position, ..etc. But what if you want to animate another property and you still want something easy and quick to use?

1.2. Implicit Animations with TweenAnimationBuilder

Back to top 👆🏼

The TweenAnimationBuilder allows you to implicitly animate any property of any widget using a Tween class. The Tween class takes its name from “Between”. It basically gives you a begin and end values to animate between. And the builder of the TweenAnimationBuilder widget gives you the animated value that you can apply to whatever property you want in the widgets you return in that builder.

Here’s an example animation:

Flutter Implicit Animation Example with TweenAnimationBuilder Widget

And here’s the code:

TweenAnimationBuilder(
duration: const Duration(milliseconds: 200),
tween: Tween<double>(begin: 0.01, end: _sliderValue),
child: Container(
decoration: BoxDecoration(
//...
),
child: Slider(
value: _sliderValue,
min: 0.01,
onChanged: (value) {
setState(() => _sliderValue = value);
},
),
),
builder: (BuildContext context, double? value, Widget? child) {
return ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 40 * (value ?? 0.01),
sigmaY: 40 * (value ?? 0.01),
),
child: child,
),
);
},
);

The _sliderValue variable changes from 0.01 to 1. So for each value change, an animation is triggered and the builder of the TweenAnimationBuilder widget is rebuilt with new values for the sigmaX & sigmaY properties of the BackdropFilter widget. (I’m using 0.01 as the min value because the BackdropFilter widget throws an error on the web when it’s given 0 values)

Here we’re using the child param of the TweenAnimationBuilder widget builder for better performance as this child rebuilds only once instead of rebuilding every time the animation is triggered.

Okay, that was the easy stuff, now to the juicy stuff!

2. Explicit Animations

Back to top 👆🏼

Remember when in implicit animations, merely changing a value inside an AnimatedFoo or TweenAnimationBuilder widget triggered an animation? Well, explicit animations don’t animate until “explicitly” being told to animate. And you tell them to animate and how to animate and “control” their animation using an AnimationController.

Similarly to implicit animations, explicit animations also have ready-to-use widgets as well as widgets with an extra level of customization for you to go wild!

But, wait, what the hell is an AnimationController? Let’s learn about it first before diving into explicit animation widgets that use it.

The AnimationController

Back to top 👆🏼

AnimationController({
double? value,
this.duration,
this.reverseDuration,
this.debugLabel,
this.lowerBound = 0.0,
this.upperBound = 1.0,
this.animationBehavior = AnimationBehavior.normal,
required TickerProvider vsync,
})

As mentioned before, the AnimationController allows you to “control” the animation. To do that, it needs a vsync value of type TickerProvider. a Ticker basically keeps track of Flutter’s frames rendering and allows the controller to follow that ticker and “animate” through it within the specified duration, while linearly producing values between the lowerBound and the upperBound values which are by default 0 & 1.

As a result, with the AnimationController, you can:

  • call forward() to play the animation forward
  • call reverse() to play the animation in reverse
  • call stop() to stop the animation
  • call repeat() to repeat the animation as long as it’s visible
  • call reset() to reset the animation to lowerBound
  • set it’s value
  • Access various getters to know the state of the animation like: isAnimating , isCompleted , isDismissed , …etc.

See the official docs for more..

Now let’s use this bad boy and see it in action 🎬

2.1. Explicit Animations with Ready-to-Use Widgets

Back to top 👆🏼

They’re called FooTransition widgets, where Foo is the animated property of the widget. Some of them are also animatable widgets of the regular widget you use, e.g. AlignTransition, PositionedTransition.

Check out this animation:

Flutter Explicit Animation Example with FooTransition Widgets

This was achieved with AlignTransition and RotationTransition widgets like so:

Code breakdown:

  • Lines 10 & 17: initializing and defining the AnimationController.
  • The vsync value of the AnimationController (line 19) takes this that comes from the SingleTickerProviderStateMixin (line 9) This mixin provides us with the TickerProvider that we talked about. This also insures that the animation is only running when the widget is visible
  • Lines 11 & 22: initializing and defining the Animation of the AlignTransition widget (line 51) using a Tween of type AlignmentGeometry. So we’re basically telling the animation that it’s going to animate from Alignment.centerLeft to Alignment.centerRight and by calling the animate method on the Tween, we’re hooking this animation with our AnimationController and returning an Animation of type AlignmentGeometry. This way instead of the animation animating between the lowerBound & upperBound of the AnimationController, it’s animating between the begin & end values of the Tween.

An Animation class is a Listenable that listens to & notifies value changes of a specified type.

  • Lines 12 & 32: initializing and defining the animation of the RotationTransition widget’s turns property (line 53). So with a 0 to 2 begin & end values, the widget will have turned twice by the end of the animation.
  • Line 20: calling repeat on the AnimationController to make it repeat indefinitely. And with reverse set to true, the animation will animate forward, then in reverse, then forward, … and so on.
  • Line 42: disposing the AnimationController in the widget’s state’s dispose lifecycle method. It’s always important to dispose our AnimationController to avoid leaks!

This is a reminder of the DartPad containing all the animations in this tutorial

But don’t worry, with a little bit of practice, it will become really easy and you’ll get the hang of it!

Here’s a full list of available FooTransition widgets:

AlignTransition

DecoratedBoxTransition

DefaultTextStyleTransition

FadeTransition

PositionedTransition

RelativePositionedTransition

RotationTransition

ScaleTransition

ScaleTransition

SizeTransition

SlideTransition

StatusTransitionWidget

Remember in implicit animations what we did if all the AnimatedFoo widgets were not enough for our animation purpose? We used the TweenAnimationBuilder to animate a property not covered in AnimatedFoo widgets. Similarly, in explicit animations, we can use the AnimatedBuilder widget to animate any and/or multiple widget properties. Or we can go a step further and use the AnimatedWidget class to create our own FooTransition!

2.2 Explicit Animations with the AnimatedBuilder widget

Back to top 👆🏼

Check out this animation:

Flutter Explicit Animation Example Using the AnimatedBuilder widget
Flutter Explicit Animation Example Using the AnimatedBuilder widget

There is no GradientTransition widget, right? So how did we achieve it? With the AnimatedBuilder widget! Here’s the code:

Here we initialized and defined an AnimationController just like before (lines 10 & 14), and used it as the animation value of the AnimatedBuilder widget (line 30). Now the AnimatedBuilder “rebuilds” for each changed value of the controller and calls the builder to return the new widget with the updated _controller.value value (line 37), causing the gradient to animate.

Of course, if you want something other than the lowerBound & upperBound values of the AnimationController, you can create your own Animation and hook it with the AnimationController and then give it to the AnimatedBuilder widget

_animation = Tween<double>(begin: 0, end: 0.5).animate(_controller);//...AnimatedBuilder(
animation: _animation,
builder: (context, child) {
//... Using the value: _animation.value
}
)

You can also make use of the child param of the AnimatedBuilder widget for better performance as it doesn’t rebuild with every animation value change.

You still with me? Hang in there, we’re almost done!

Now we’re going to go one step further and create our own FooTransition widget using the AnimatedWidget class!

2.3 Explicit Animations with the AnimatedWidget Class

Back to top 👆🏼

Let me tell you a secret that is not very secret. Go to the source code of any FooTransition widget, what do you see?

RotationTransition Widget Source Code

😱 It extends an AnimatedWidget class, and from what we see, the Animation type parameter (in this case turns ) is passed as a listenable to the super class:

AnimatedWidget class

And the AnimatedWidget is basically a StatefulWidget! So we can do the exact same!

Let’s create our own GradientTransition widget then:

class GradientTransition extends AnimatedWidget {
final Animation<double> stop;

const GradientTransition({
Key? key,
required this.stop,
}) : super(key: key, listenable: stop);

@override
Widget build(BuildContext context) {
return Container(
height: 100,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: const [purple, pink, yellow],
stops: [0, stop.value, 1],
),
),
);
}
}

And to use it, we simply pass it the AnimationController:

GradientTransition(stop: _controller),

And that’s it!

If you survived to this point, then you have enough knowledge to create an unlimited amount of Flutter animations varying from very simple to very complex. All you need is a bit of practice and the sky is your limit!

Choosing the Right Animation Approach

Back to top 👆🏼

But hang on, how do you know which of the many ways we went over above you should choose for your animation? Well, the amazing people on the Flutter team created a video and a decision tree to help you with that. And I’m going to do my best to summarize it for you.

1. Drawing-based vs. Code-based

Your first choice will be between Drawing-based & Code-based animations, for that you can ask yourself if your animation is more like a drawing (use drawing-based, 3rd party packages, more on that shortly) or is it related to layout, widgets, widget styles, colors, borders, text, ..etc (use code-based, discussed above)

2. Implicit vs. Explicit

Your next choice will be between Implicit & Explicit animations, for which you have multiple criteria to decide:

  1. Infinitely repeated animation
  2. Discontinuous animation: the animation doesn’t return to its starting point.
  3. Multiple widgets are animating together.

If your animation has any of the above criteria, you should use Explicit animations

3. Built-in vs. Custom Widgets

Your last choice is between built-in widgets (AnimatedFoo & FooTransition widgets) and custom widgets (TweenAnimationBuilder & AnimatedBuilder/AnimatedWidget). This is as simple as viewing this list and considering if the property you want to animate already has a built-in widget (in which you use that) or not (in which you create your own)

List of AnimatedFoo & FooTransition Widgets
List of AnimatedFoo & FooTransition Widgets

Animations Using 3rd Party Packages

But what if you want to use drawing-based animations in your app? Well, you saved yourself some coding here 🫢, and Flutter is also amazing in this! With great packages out there, such as Rive and Lottie, It allows you to seamlessly integrate with 3rd party animations and add them to your app. You’ll need a graphic designer/motion graphics designer, or you can download/purchase animations created by the community and use them in your app quickly and easily.

I will write a dedicated article for using 3rd party packages for animations in Flutter. For now, here are some useful links:

That’s it from me! Thank you for reading this article. I hope this will be your go-to guide when you want to add an animation to your Flutter app. And when you do, go wild!

https://twitter.com/FlutterComm

--

--

Roaa Khaddam
Flutter Community

Software Engineer | 💙 Flutter / Dart Google Developer Expert