Skip to content

Expert · Animations and performance · topic 36 of 50 · 35 min

Explicit animations

Explanation

Explicit animations give full control: an AnimationController (created in initState with vsync from SingleTickerProviderStateMixin) runs from 0 to 1 over a duration, and you can forward, reverse, repeat or stop it. Tweens map that range to sizes, colours or offsets, CurvedAnimation adds easing, and AnimatedBuilder (or transition widgets like FadeTransition) rebuilds only the animated part. Always dispose the controller.

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

PieceRole
AnimationControllerProduces 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
TweenMaps 0 to 1 onto real values: 0 to 300 pixels, white to red
CurvedAnimationApplies a curve such as easeInOut to the controller's progress
AnimatedBuilder / XTransitionRebuilds only the animated widget on every tick
dart
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),
    );
  }
}
A red "LIVE" dot that gently grows and shrinks.

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

dart
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,
  ),
)
Only the Transform is rebuilt each frame; the icon (child) is created once.

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.
Think of it like this: An AnimationController is like a music player's progress bar from 0 to 100 percent. Play, pause, rewind and loop are its buttons. Tweens are like the different meanings of that progress: the lights getting brighter, the volume rising, the stage curtain moving. vsync makes sure the player only runs while someone is in the hall.

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

AnimationController

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.

dart
// 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);
TickerFuture lets you await the end of an animation.

Practice (0/3 done)

Task 1 · Question

Where should an AnimationController be created and disposed?

Task 2 · Question

What does vsync: this need from the State class?

Task 3 · Practice

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

Question 1

1.What range of values does an AnimationController produce by default?

Question 2

2.Which call loops an animation back and forth?

Question 3

3.Why pass a child to AnimatedBuilder?

Question 4

4.Which mixin is used for a State with several AnimationControllers?

Read more (free)

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

Answer: duration (and optionally curve)

They handle the rest.

From Implicit animations

What is a good duration for a button hover effect?Related

Answer: About 200ms

Short UI motion (150-300ms) feels responsive.

From Transitions and animations

Which package plays After Effects animations exported as JSON?Related

Answer: lottie

Lottie files are JSON.

From Hero, page transitions and Lottie or Rive

Which method runs once when a State is created?Related

Answer: initState

Use it for one-time setup.

From Stateless and stateful widgets

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

  1. 2 more topics in “Animations and performance” before its exam: Hero, page transitions and Lottie or Rive, Performance.
  2. Module 9 exam: Animations and performance · 12 questions · 25 min, without help. 4 topics of this module still to finish first.
  3. Then the next module, Responsive design and testing. 50 topics left in the course before the final exam.

← Previous: Implicit animations