Articles

How to Create Flutter Animations: Complete Tutorial

Animations are what make apps feel alive. They guide users, add polish, and make experiences more engaging, whether it’s a transition, a background, or a number counting up with excitement.

In this tutorial, you’ll build four working Flutter animation examples: an animated container that changes size and color, an explicit color transition animation, a particle-based animated background, and a smooth number counter. Each example includes complete code you can run immediately on your emulator to see animations in action.

  • This course will introduce learners to the Flutter framework with interactive lessons on basic app components.
    • Beginner Friendly.
      1 hour
  • Learn how to make your website shake, slide, and grow with CSS transitions.
    • Beginner Friendly.
      1 hour

What are flutter animations?

Flutter animations add life to your app’s UI by creating smooth transitions, effects, and movements. There are two main types of animations in Flutter:

  • Implicit animations: Easy to use, where we only specify the end values, and Flutter takes care of the motion (e.g., AnimatedContainer, AnimatedOpacity).
  • Explicit animations: Give us complete control over timing, curves, and sequencing (e.g., AnimationController, Tween, and AnimatedBuilder).

We’ll work with both the types of animations in this tutorial. Let’s get started with building our app now.

Setting up your flutter project

Let’s begin by setting up your project environment.

Step 1: Create a new flutter project

Open your terminal and run:

flutter create flutter_animation_tutorial
cd flutter_animation_tutorial

Step 2: Open the project

Open the newly created project in VS Code or Android Studio.

Step 3: Create a folder for screens

Inside your lib folder, create a new folder named screens.

Your structure should now look like this:

Flutter animation app structure

Flutter animation example: building animated container

We’ll begin with a simple implicit animation using AnimatedContainer. This widget automatically animates between old and new property values, you just change the values, and Flutter handles the smooth transition!

Step 1: Create a new file

Inside the screens folder, create a file named animated_container_screen.dart.

Step 2: Writing the code

We will use the AnimatedContainer widget to create a smooth shape and color animation. Each time you press the floating action button, the container will smoothly change its size and color between blue and orange in over one second.

import 'package:flutter/material.dart';
class AnimatedContainerScreen extends StatefulWidget {
const AnimatedContainerScreen({super.key});
@override
State<AnimatedContainerScreen> createState() => _AnimatedContainerScreenState();
}
class _AnimatedContainerScreenState extends State<AnimatedContainerScreen> {
double _size = 100.0;
Color _color = Colors.blue;
void _changeShape() {
setState(() {
_size = _size == 100 ? 200 : 100;
_color = _color == Colors.blue ? Colors.orange : Colors.blue;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Animated Container')),
body: Center(
child: AnimatedContainer(
duration: const Duration(seconds: 1),
curve: Curves.easeInOut,
height: _size,
width: _size,
color: _color,
child: const Center(
child: Text('Tap Me!', style: TextStyle(color: Colors.white)),
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _changeShape,
child: const Icon(Icons.play_arrow),
),
);
}
}

What’s happening here in the code:

  • AnimatedContainer animates its properties automatically.
  • When setState() changes _size or _color, the container smoothly transitions instead of jumping instantly.
  • The duration parameter controls how long the animation takes.
  • Curves.easeInOut makes the animation feel natural.

Step 3: Connecting the screen

Open the main.dart file and paste the following code to run the animation screen we just built.

import 'package:flutter/material.dart';
import 'screens/animated_container_screen.dart';
void main() {
runApp(const AnimationApp());
}
class AnimationApp extends StatelessWidget {
const AnimationApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: AnimatedContainerScreen(),
);
}
}

Step 4: Run the app

Run the following command to compile the app:

flutter run

Flutter animated container showcasing smooth color and size transition example

You’ll see a blue square that expands and changes color when you tap the floating button, giving you your first animation! Let’s now see how Explicit animations work now.

Using Flutter explicit animations with animation controller

Explicit animations give you complete control over each frame. Think of AnimationController as a movie director that manages when the animation plays, pauses, reverses, or repeats. Let’s implement it locally in our IDE now.

Step 1: Create a new file

Create a new file called explicit_animation_screen.dartin the screens folder.

Step 2: Writing the code

In this tutorial, we will learn how to create a color-changing animation using Flutter’s explicit animation system. We will utilize an AnimationController and a ColorTween to smoothly transition a square’s color between red and green. The animation will continuously repeat in a loop, reversing direction each time to create a seamless back-and-forth effect.

This example will demonstrate how to build explicit animations, allowing us to control the animation’s behavior, timing, and playback manually with the AnimationController. This approach provides a deeper understanding of how animations work under the hood and offers more flexibility compared to implicit animations.

import 'package:flutter/material.dart';
class ExplicitAnimationScreen extends StatefulWidget {
const ExplicitAnimationScreen({super.key});
@override
State<ExplicitAnimationScreen> createState() => _ExplicitAnimationScreenState();
}
class _ExplicitAnimationScreenState extends State<ExplicitAnimationScreen>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<Color?> _colorAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
)..repeat(reverse: true);
_colorAnimation = ColorTween(
begin: Colors.red,
end: Colors.green,
).animate(_controller);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Explicit Animation')),
body: Center(
child: AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Container(
height: 150,
width: 150,
color: _colorAnimation.value,
);
},
),
),
);
}
}

Let’s break down the explicit animations code we just wrote:

  • AnimationController: Controls animation timing and playback.
  • Tween: Defines value interpolation (from red to green).
  • AnimatedBuilder: Rebuilds efficiently as values change.
  • vsync: Keeps the animation synchronized with screen refresh.
  • repeat(reverse: true): Loops the animation back and forth.

Step 3: View this screen

Open the main.dart file and change the home child to following:

home: ExplicitAnimationScreen(),

The next step is to import the Explicit animation screen we’ve created. To do this, simply add this import line at the top of your code:

import 'screens/explicit_animation_screen.dart';

Run the app to see a looping red-green color transition.

Flutter explicit animation demo demonstrating a red to green color transition

Creating an Animated Background

Let’s create a moving background using the animated_background package.

Step 1: Add dependency

Open the pubspec.yaml file and paste the following dependency name there.

animated_background: ^2.0.0

Then open the terminal and run:

flutter pub get

Step 2: Create a file

lib/screens/animated_background_screen.dart

Step 3: Writing the code

We’re going to learn how to create an animated particle background. We’ll use the animated_background package, which makes it simple to include moving effects like floating particles behind your widgets.

import 'package:flutter/material.dart';
import 'package:animated_background/animated_background.dart';
class AnimatedBackgroundScreen extends StatefulWidget {
const AnimatedBackgroundScreen({super.key});
@override
State<AnimatedBackgroundScreen> createState() => _AnimatedBackgroundScreenState();
}
class _AnimatedBackgroundScreenState extends State<AnimatedBackgroundScreen>
with TickerProviderStateMixin {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Animated Background')),
body: AnimatedBackground(
vsync: this,
behaviour: RandomParticleBehaviour(
options: const ParticleOptions(
baseColor: Colors.purple,
spawnOpacity: 0.3,
spawnMinSpeed: 30.0,
spawnMaxSpeed: 70.0,
particleCount: 50,
),
),
child: const Center(
child: Text(
'Flutter Animated Background',
style: TextStyle(fontSize: 20, color: Colors.white),
),
),
),
);
}
}

Let’s understand the particle system:

  • RandomParticleBehaviour: Moves particles randomly for an organic effect.
  • spawnOpacity: Adjusts transparency.
  • Speed range: Creates depth and realism.
  • particleCount: Controls the number of particles.

Running the app

Open the main.dart file and replace the last screen with AnimateBackgroundScreen like:

home: AnimatedBackgroundScreen(),

And, import the screen on top so we can call the screen on the home page.

import 'screens/animated_background_screen.dart';

Run the app and you’ll see floating purple particles, this is great for splash screens or ambient backgrounds.

Flutter animated background example – floating particle animation effect in Flutter

Flutter number animation implementation

Let’s animate numbers using TweenAnimationBuilder.

Step 1: Create file

Inside the screens folder, create a file called number_animation_screen.dart.

Step 2: Implementing number animation

Let’s create a smooth number-counting animation using the TweenAnimationBuilder widget.

In this code, we’ll set the number to start from 0 and animate it up to 100 when the screen opens, over a duration of 5 seconds. The TweenAnimationBuilder automatically interpolates values between the start and end points and rebuilds the widget tree on each frame.

The animated value appears at the center of the screen in bold, large text, producing a clean and attractive number of animation effects.

import 'package:flutter/material.dart';
class NumberAnimationScreen extends StatelessWidget {
const NumberAnimationScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Number Animation')),
body: Center(
child: TweenAnimationBuilder(
tween: Tween<double>(begin: 0, end: 100),
duration: const Duration(seconds: 5),
builder: (context, value, child) {
return Text(
value.toInt().toString(),
style: const TextStyle(fontSize: 50, fontWeight: FontWeight.bold),
);
},
),
),
);
}
}

Let’s now see why we specifically used TweenAnimationBuilder to implement the above animation:

  • No boilerplate: No controller or disposal needed.
  • Automatic cleanup handled by Flutter.
  • Smooth interpolation between start and end values.
  • Flexible: Works with colors, sizes, and numbers.

Step 3: Run and observe

Open the main.dart file and replace the older screen with new number animation screen like:

home: NumberAnimationScreen(),

You’ll see numbers count smoothly from 0 to 100 in 5 seconds.

Flutter number animation demo increasing number animation in Flutter app

How to decide which flutter animation to use

Choosing the right animation tool in Flutter can be confusing, but we’ll now see how to decide on the type of animation for our app.

Step 1: Is your animation like a drawing or standard layout?

This is the first and most important question.

  • Is your animation more like a drawing?

  • Does it involve complex vector graphics, raster images, or motion that is hard to express with standard widgets (like Container, Row, Column)?

If YES (It’s like a drawing):

You have two main options:

Use an Animation Framework (like Lottie):

This is the best choice if you are working with a design team, using animations exported from tools like Adobe After Effects, or if the motion is too complex to code by hand. Lottie (which replaced Flare) reads JSON animation files and handles all the rendering for you.

Use CustomPainter:

This is the low-level, high-performance solution. Choose this if you are not using a design tool and instead want to code the drawing logic yourself. This gives you complete control over the canvas to draw shapes, lines, and images, and is perfect for explicit, high-performance animations.

If NO (It’s standard layout movement):

If your animation involves changing the properties of standard widgets (like size, color, opacity, or position), move on to Step 2.

Step 2: Are you animating text?

  • If YES: Are you specifically animating the text style (e.g., color, font size, weight)?

  • YES: Use the implicit widget AnimatedDefaultTextStyle. It will automatically animate any changes to the text style.

  • NO: If you’re animating something else about the text (like its position), or your text animation is more complex, continue to Step 3.

Step 3: Implicit vs. Explicit Animation (The Core Decision)

This is the main branching point for most widget animations.

  • Choose IMPLICIT Animations (The “Yes” path) if:

    • Your animation is simple and “always goes forwards” (e.g., animates from value A to B).

    • You don’t need to stop, reverse, or loop the animation.

    • You are animating a single property on a single child.

    • This is the “fire-and-forget” approach.

  • Choose EXPLICIT Animations (The “No” path) if:

    • You need full control over the animation.

    • You need to repeat (loop), reverse, or stop the animation.

    • You want to chain multiple animations together.

    • This approach requires an AnimationController that you must manage.

Step 4: The implicit animation path

You’ve chosen the simple, implicit path.

  • First, ask: “Is there a built-in AnimatedFoo widget for what I want?”

    • Flutter has many of these, such as AnimatedContainer, AnimatedOpacity, AnimatedPositioned, and AnimatedPadding.

    • If YES: Use that built-in AnimatedFoo widget. This is the easiest way to get an animation.

    • If NO: There is no pre-built widget for the property you want to animate.

  • Second, use: TweenAnimationBuilder.

This is the general-purpose implicit animation widget. You give it a tween (a start and end value), a duration, and a builder function, and it automatically handles the animation.

Step 5: The explicit animation path

You’ve chosen the explicit path for full control.

  • First, ask: “Is there a built-in FooTransition widget for what I want?”

    • These widgets are built to work with your AnimationController. Examples include FadeTransition, ScaleTransition, SlideTransition, and RotationTransition.

    • If YES: Use that built-in FooTransition widget and pass it your AnimationController.

  • If NO: You need a custom explicit animation. You have two main choices:

    • AnimatedBuilder: Use this if you want to apply your animation within an existing widget’s build method. It’s a highly flexible widget that rebuilds its child (or builder) on every tick of the animation, without rebuilding the entire parent widget. This is a very common and recommended choice.

    • Subclass AnimatedWidget: Use this if you want to create a new, reusable, standalone animation widget that encapsulates its own animation logic.

Best practices for flutter animations

  • Make sure you keep animations simple and meaningful; remember, more animations don’t always mean a better user experience.

  • Use implicit animations for quick effects and explicit ones for control.

  • Always dispose controllers to prevent memory leaks.

  • Test on real devices for accurate performance.

  • Avoid excessive animations to prevent distraction.

  • Use const constructors for efficiency.

  • Use AnimatedSwitcher for widget transitions.

  • Profile animations with Flutter DevTools.

Conclusion

You’ve created four types of animations in this tutorial so far: container transitions, explicit controls, animated backgrounds, and number counters. Each provides a different level of control and creativity.

Your next steps to improve could include:

  • Combining multiple animations.

  • Experiment with curves like bounce or elastic.

  • Incorporate gesture-driven animations.

  • Explore hero transitions for smooth navigation.

To learn more about Flutter animations and other official animations available, you can visit the official Flutter animations documentation by Google and explore different types of animations there.

Frequently asked questions

1. What are implicit and explicit animations in Flutter?

Implicit animations change properties automatically (like AnimatedContainer). Explicit ones use AnimationController for precise control.

2. How can I create moving backgrounds in Flutter?

Use packages like animated_background or flutter_animate, or use CustomPaint for full control.

3. How do I animate numbers smoothly?

Use TweenAnimationBuilder or AnimatedBuilder with tweens for smooth numeric transitions.

4. Do animations affect app performance?

Yes, if overused. Limit rebuilds, use const constructors, and test on devices.

5. Which package is best for Flutter animations?

  • Beginner: Built-in widgets (AnimatedContainer, TweenAnimationBuilder)
  • Advanced: flutter_animate for complex effects
  • Backgrounds: animated_background
  • Custom: CustomPaint with AnimationController
Codecademy Team

'The Codecademy Team, composed of experienced educators and tech experts, is dedicated to making tech skills accessible to all. We empower learners worldwide with expert-reviewed content that develops and enhances the technical skills needed to advance and succeed in their careers.'

Meet the full team

Learn more on Codecademy