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.
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, andAnimatedBuilder).
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_tutorialcd 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 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});@overrideState<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;});}@overrideWidget 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:
AnimatedContaineranimates its properties automatically.- When
setState()changes_sizeor_color, the container smoothly transitions instead of jumping instantly. - The
durationparameter controls how long the animation takes. Curves.easeInOutmakes 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});@overrideWidget 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

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});@overrideState<ExplicitAnimationScreen> createState() => _ExplicitAnimationScreenState();}class _ExplicitAnimationScreenState extends State<ExplicitAnimationScreen>with SingleTickerProviderStateMixin {late AnimationController _controller;late Animation<Color?> _colorAnimation;@overridevoid 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);}@overridevoid dispose() {_controller.dispose();super.dispose();}@overrideWidget 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.

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});@overrideState<AnimatedBackgroundScreen> createState() => _AnimatedBackgroundScreenState();}class _AnimatedBackgroundScreenState extends State<AnimatedBackgroundScreen>with TickerProviderStateMixin {@overrideWidget 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 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});@overrideWidget 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.

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
AnimationControllerthat you must manage.
Step 4: The implicit animation path
You’ve chosen the simple, implicit path.
First, ask: “Is there a built-in
AnimatedFoowidget for what I want?”Flutter has many of these, such as
AnimatedContainer,AnimatedOpacity,AnimatedPositioned, andAnimatedPadding.If YES: Use that built-in
AnimatedFoowidget. 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
FooTransitionwidget for what I want?”These widgets are built to work with your
AnimationController. Examples includeFadeTransition,ScaleTransition,SlideTransition, andRotationTransition.If YES: Use that built-in
FooTransitionwidget and pass it yourAnimationController.
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’sbuildmethod. 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
constconstructors for efficiency.Use
AnimatedSwitcherfor 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
bounceorelastic.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_animatefor complex effects - Backgrounds:
animated_background - Custom:
CustomPaintwithAnimationController
'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 teamRelated articles
- Article
Essential Flutter Widgets Every Developer Should Know
Learn essential Flutter widgets, including Container, Text, Scaffold, and more. Covers Stateless vs Stateful widgets with examples. - Article
REST API in Flutter: A beginner’s guide to fetching data
Learn to fetch data from REST API in Flutter. Step-by-step tutorial with code examples for beginners. - Article
Flutter Tutorial for Beginners: Build Your First App
Learn Flutter app development with this beginner tutorial. Build a habit tracker app with UI design, state management, and data storage.
Learn more on Codecademy
- 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
- Make your Phaser game stand out visually using animations and camera effects.
- Intermediate.2 hours
- What are flutter animations?
- Setting up your flutter project
- Flutter animation example: building animated container
- Using Flutter explicit animations with animation controller
- Creating an Animated Background
- Flutter number animation implementation
- How to decide which flutter animation to use
- Best practices for flutter animations
- Conclusion
- Frequently asked questions