Expert · Animations and performance · topic 36 of 50 · 35 min
Explicit animations
Explanation
When implicit is not enough
Implicit animations run when a value changes. Some effects need more control: a pulsing "live" dot that repeats forever, a loading animation that plays while data loads, an animation the user can pause or reverse, or several properties moving in a coordinated sequence. For these, you drive the animation yourself with an AnimationController.
The pieces
| Piece | Role |
|---|---|
| AnimationController | Produces values from 0.0 to 1.0 over a duration; can forward, reverse, repeat and stop |
| vsync (TickerProvider) | Ties the controller to screen refreshes so it does not run when the screen is hidden |
| Tween | Maps 0 to 1 onto real values: 0 to 300 pixels, white to red |
| CurvedAnimation | Applies a curve such as easeInOut to the controller's progress |
| AnimatedBuilder / XTransition | Rebuilds only the animated widget on every tick |
class PulsingDot extends StatefulWidget {
const PulsingDot({super.key});
@override
State<PulsingDot> createState() => _PulsingDotState();
}
class _PulsingDotState extends State<PulsingDot> with SingleTickerProviderStateMixin {
late final AnimationController _controller;
late final Animation<double> _scale;
@override
void initState() {
super.initState();
_controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 800))
..repeat(reverse: true); // 0 -> 1 -> 0 forever
_scale = Tween<double>(begin: 0.8, end: 1.2)
.animate(CurvedAnimation(parent: _controller, curve: Curves.easeInOut));
}
@override
void dispose() {
_controller.dispose(); // ALWAYS dispose
super.dispose();
}
@override
Widget build(BuildContext context) {
return ScaleTransition(
scale: _scale,
child: const CircleAvatar(radius: 8, backgroundColor: Colors.red),
);
}
}SingleTickerProviderStateMixin is a mixin (module 2) that lets the State act as the vsync for one controller. Use TickerProviderStateMixin if the State has several controllers. The mixin pauses tickers when the widget is not visible, saving battery.
Flutter ships ready transition widgets that take an Animation directly: FadeTransition (opacity), ScaleTransition, SlideTransition (an Offset), RotationTransition and SizeTransition. They are efficient because they update only what changes each frame, without calling build on your widget.
AnimatedBuilder for custom effects
AnimatedBuilder(
animation: _controller,
child: const Icon(Icons.sync, size: 40), // built once, reused every frame
builder: (context, child) => Transform.rotate(
angle: _controller.value * 2 * 3.14159,
child: child,
),
)Start with implicit animations; reach for a controller only when you need repeat, pause or reverse.
Controlling playback
- _controller.forward() plays from the current value to 1.
- _controller.reverse() plays back to 0.
- _controller.repeat(reverse: true) loops back and forth.
- _controller.stop() pauses; _controller.reset() jumps to 0.
- forward() returns a Future (TickerFuture) you can await to run something when it finishes.
Common mistakes
- Not disposing the controller: "AnimationController.dispose() called... was never disposed" warnings and leaked tickers.
- Creating the controller in build: a new controller on every rebuild. Create it in initState.
- Calling setState on every tick and rebuilding the whole screen. Use AnimatedBuilder or transition widgets.
- Forgetting the mixin: "The argument type ... can't be assigned to the parameter type TickerProvider".
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Explicit animations · 1/6
Explicit animations give full control: repeat, pause, reverse and sequence.
Prefer a video by a teacher? Find free videos on “flutter explicit animation animationcontroller tween animatedbuilder vsync” on YouTube ↗
In real life: A loading animation for a payment
While a UPI payment is confirming, a payments app shows a circle that rotates continuously and a tick that scales in when the payment succeeds. One AnimationController repeats the rotation; when the result arrives, the code stops it and plays a second controller forward for the tick. Both controllers are disposed when the screen closes.
// success: stop spinning and pop in the tick
_spin.stop();
await _tick.forward(); // wait for the tick animation to finish
if (mounted) Navigator.pop(context, true);Practice (0/3 done)
Where should an AnimationController be created and disposed?
What does vsync: this need from the State class?
Build a "breathing exercise" screen: a circle that grows for 4 seconds and shrinks for 4 seconds repeatedly (repeat(reverse: true)), a Start/Pause button that calls repeat or stop, and text that shows "Breathe in" or "Breathe out" depending on the controller's status. Use AnimatedBuilder and dispose the controller.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Hero, page transitions and Lottie or RiveAnimations and performance · same module
- PerformanceAnimations and performance · same module
- Transitions and animationsFrontend Web Development · CSS layout and responsive design
- Widget testsResponsive design and testing
- for loops and range()Python Programming · Loops: repeating work
- Timers: running code laterFrontend Web Development · JavaScript in the browser: DOM and events
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
What range of values does an AnimationController produce by default?
Answer: 0.0 to 1.0
Tweens map it to real values.
Which call loops an animation back and forth?
Answer: repeat(reverse: true)
repeat with reverse goes 0 to 1 to 0.
Why pass a child to AnimatedBuilder?
Answer: The child is built once and reused, so each frame does less work
Only the builder part rebuilds per frame.
Which mixin is used for a State with several AnimationControllers?
Answer: TickerProviderStateMixin
The plural version supports many tickers.
What two parameters do implicit animation widgets need besides their normal properties?Related
What is a good duration for a button hover effect?Related
Which package plays After Effects animations exported as JSON?Related
Which method runs once when a State is created?Related
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 2 more topics in “Animations and performance” before its exam: Hero, page transitions and Lottie or Rive, Performance.
- Module 9 exam: Animations and performance · 12 questions · 25 min, without help. 4 topics of this module still to finish first.
- Then the next module, Responsive design and testing. 50 topics left in the course before the final exam.