Skip to content
Blog

Implicit Animations in Flutter: Motion Without an AnimationController

Implicitly animated widgets let you add motion by changing a value — no AnimationController or Ticker required. Learn how AnimatedContainer, AnimatedOpacity, and TweenAnimationBuilder fit together.

Published on • October 21, 2026

AI Assistant

The fastest way to make a Flutter app feel unfinished is to have state change and the UI jump instantly to its new value. Motion communicates continuity — it tells the user what changed and where it went. The surprising part for developers arriving from frameworks where animation means timelines and easing curves is how little code Flutter needs for the common cases, because a whole family of widgets animates implicitly.

Source: Implicit animations, The Flutter Team, docs.flutter.dev.

What “implicit” means

Implicit animations come from the ImplicitlyAnimatedWidget class. The model is simple: you hand the widget a target value plus a duration and an optional curve, and when that target value changes — typically via setState — the widget animates to the new value on its own. There is no AnimationController to create, no Ticker to manage, no dispose to clean up.

AnimatedOpacity(
  opacity: _visible ? 1 : 0,
  duration: const Duration(milliseconds: 500),
  curve: Curves.easeInOut,
  child: const FlutterLogo(size: 100),
)

Flip _visible inside setState, and the logo fades rather than snapping. The widget owns the interpolation between the old and new values.

The family you actually use

The implicitly animated widgets cover the properties you change most often. Beyond AnimatedOpacity there is AnimatedContainer (color, size, padding, margin, decoration, constraints in one), AnimatedPadding, AnimatedPositioned (for Stack layouts), AnimatedSwitcher (cross-fades between different children as they swap), and siblings for alignment, opacity, transform, and more.

AnimatedContainer is the workhorse, because a single widget can animate a whole set of visual properties at once when a value changes:

AnimatedContainer(
  duration: const Duration(milliseconds: 300),
  curve: Curves.easeOut,
  width: _expanded ? 240 : 120,
  height: _expanded ? 240 : 120,
  decoration: BoxDecoration(
    color: _expanded ? Colors.blue : Colors.grey,
    borderRadius: BorderRadius.circular(_expanded ? 24 : 8),
  ),
)

One boolean drives size, color, and corner radius simultaneously, and every property eases in concert.

When nothing fits: TweenAnimationBuilder

The built-in widgets stop at their fixed property sets. For anything else — a custom painter parameter, a computed value, a property those widgets do not expose — TweenAnimationBuilder gives you the same implicit model without a controller. You supply a Tween describing the range and a builder that receives the animated value:

TweenAnimationBuilder<double>(
  tween: Tween(begin: 0, end: 1),
  duration: const Duration(milliseconds: 800),
  builder: (context, value, child) => Opacity(
    opacity: value,
    child: child,
  ),
  child: const MyContent(),
)

This is the escape hatch that keeps you out of explicit-animation territory for the large class of “just animate this one number” cases. All implicit animations extend ImplicitlyAnimatedWidget, so the mental model is uniform whether you are using a shipped widget or a custom builder.

Choosing curve and duration

Two knobs control feel. duration sets how long the transition takes; curve sets its easing. Flutter ships a large set of named Curves — easeInOut, easeOut, bounceOut, elasticIn, and many more. The guidance is conservative: match duration to the size of the change (small layout tweaks want short durations; large spatial moves want longer ones), and reach for expressive curves sparingly. A subtle easeOut reads as polished; an over-the-top bounce on routine state changes reads as toy-like.

Key takeaways

Implicit animations let you add motion by changing a target value and letting the widget interpolate — no AnimationController or Ticker involved. The family (AnimatedContainer, AnimatedOpacity, AnimatedPositioned, AnimatedSwitcher, and friends) covers most everyday cases, and TweenAnimationBuilder extends the same model to any property those widgets do not expose. Pick duration and curve deliberately, and you get continuity and polish for a fraction of the code explicit animation demands.

Further reading