- Implementing Flutter Animations
- Contents
- Core Concepts
- Animation Strategies
- Workflows
- Implementing Implicit Animations
- Implementing Explicit Animations
- Implementing Hero Transitions
- Implementing Physics-Based Animations
- Examples
- Core Concepts
- Manage Flutter animations using the core typed
- Animation
- system. Do not manually calculate frames; rely on the framework's ticker and interpolation classes.
- Animation
-
- Treat this as an abstract representation of a value that changes over time. It holds state (completed, dismissed) and notifies listeners, but knows nothing about the UI.
- AnimationController
-
- Instantiate this to drive the animation. It generates values (typically 0.0 to 1.0) tied to the screen refresh rate. Always provide a
- vsync
- (usually via
- SingleTickerProviderStateMixin
- ) to prevent offscreen resource consumption. Always
- dispose()
- controllers to prevent memory leaks.
- Tween
-
- Define a stateless mapping from an input range (usually 0.0-1.0) to an output type (e.g.,
- Color
- ,
- Offset
- ,
- double
- ). Chain tweens with curves using
- .animate()
- .
- Curve
- Apply non-linear timing (e.g.,
Curves.easeIn
,
Curves.bounceOut
) to an animation using a
CurvedAnimation
or
CurveTween
.
Animation Strategies
Apply conditional logic to select the correct animation approach:
If animating simple property changes (size, color, opacity) without playback control:
Use
Implicit Animations
(e.g.,
AnimatedContainer
,
AnimatedOpacity
,
TweenAnimationBuilder
).
If requiring playback control (play, pause, reverse, loop) or coordinating multiple properties:
Use
Explicit Animations
(e.g.,
AnimationController
with
AnimatedBuilder
or
AnimatedWidget
).
If animating elements between two distinct routes:
Use
Hero Animations
(Shared Element Transitions).
If modeling real-world motion (e.g., snapping back after a drag):
Use
Physics-Based Animations
(e.g.,
SpringSimulation
).
If animating a sequence of overlapping or delayed motions:
Use
Staggered Animations
(multiple
Tween
s driven by a single
AnimationController
using
Interval
curves).
Workflows
Implementing Implicit Animations
Use this workflow for "fire-and-forget" state-driven animations.
Task Progress:
Identify the target properties to animate (e.g., width, color).
Replace the static widget (e.g.,
Container
) with its animated counterpart (e.g.,
AnimatedContainer
).
Define the
duration
property.
(Optional) Define the
curve
property for non-linear motion.
Trigger the animation by updating the properties inside a
setState()
call.
Run validator -> review UI for jank -> adjust duration/curve if necessary.
Implementing Explicit Animations
Use this workflow when you need granular control over the animation lifecycle.
Task Progress:
Add
SingleTickerProviderStateMixin
(or
TickerProviderStateMixin
for multiple controllers) to the
State
class.
Initialize an
AnimationController
in
initState()
, providing
vsync: this
and a
duration
.
Define a
Tween
and chain it to the controller using
.animate()
.
Wrap the target UI in an
AnimatedBuilder
(preferred for complex trees) or subclass
AnimatedWidget
.
Pass the
Animation
object to the
AnimatedBuilder
's
animation
property.
Control playback using
controller.forward()
,
controller.reverse()
, or
controller.repeat()
.
Call
controller.dispose()
in the
dispose()
method.
Run validator -> check for memory leaks -> ensure
dispose()
is called.
Implementing Hero Transitions
Use this workflow to fly a widget between two routes.
Task Progress:
Wrap the source widget in a
Hero
widget.
Assign a unique, data-driven
tag
to the source
Hero
.
Wrap the destination widget in a
Hero
widget.
Assign the
exact same
tag
to the destination
Hero
.
Ensure the widget trees inside both
Hero
widgets are visually similar to prevent jarring jumps.
Trigger the transition by pushing the destination route via
Navigator
.
Implementing Physics-Based Animations
Use this workflow for gesture-driven, natural motion.
Task Progress:
Set up an
AnimationController
(do not set a fixed duration).
Capture gesture velocity using a
GestureDetector
(e.g.,
onPanEnd
providing
DragEndDetails
).
Convert the pixel velocity to the coordinate space of the animating property.
Instantiate a
SpringSimulation
with mass, stiffness, damping, and the calculated velocity.
Drive the controller using
controller.animateWith(simulation)
.
Examples
class
StaggeredAnimationDemo
extends
StatefulWidget
{
@override
State
<
StaggeredAnimationDemo
createState ( ) =
_StaggeredAnimationDemoState ( ) ; } class _StaggeredAnimationDemoState extends State < StaggeredAnimationDemo
with SingleTickerProviderStateMixin { late AnimationController _controller ; late Animation < double
_widthAnimation ; late Animation < Color ?
_colorAnimation ; @override void initState ( ) { super . initState ( ) ; _controller = AnimationController ( duration : const Duration ( seconds : 2 ) , vsync : this , ) ; // Staggered width animation (0.0 to 0.5 interval) _widthAnimation = Tween < double
( begin : 50.0 , end : 200.0 ) . animate ( CurvedAnimation ( parent : _controller , curve : const Interval ( 0.0 , 0.5 , curve : Curves . easeIn ) , ) , ) ; // Staggered color animation (0.5 to 1.0 interval) _colorAnimation = ColorTween ( begin : Colors . blue , end : Colors . red ) . animate ( CurvedAnimation ( parent : _controller , curve : const Interval ( 0.5 , 1.0 , curve : Curves . easeOut ) , ) , ) ; _controller . forward ( ) ; } @override void dispose ( ) { _controller . dispose ( ) ; // CRITICAL: Prevent memory leaks super . dispose ( ) ; } @override Widget build ( BuildContext context ) { return AnimatedBuilder ( animation : _controller , builder : ( context , child ) { return Container ( width : _widthAnimation . value , height : 50.0 , color : _colorAnimation . value , ) ; } , ) ; } } Route createCustomRoute ( Widget destination ) { return PageRouteBuilder ( pageBuilder : ( context , animation , secondaryAnimation ) =
destination , transitionsBuilder : ( context , animation , secondaryAnimation , child ) { const begin = Offset ( 0.0 , 1.0 ) ; // Start from bottom const end = Offset . zero ; const curve = Curves . easeOut ; final tween = Tween ( begin : begin , end : end ) . chain ( CurveTween ( curve : curve ) ) ; final offsetAnimation = animation . drive ( tween ) ; return SlideTransition ( position : offsetAnimation , child : child , ) ; } , ) ; } // Usage: Navigator.of(context).push(createCustomRoute(const NextPage()));
flutter-animating-apps
安装
npx skills add https://github.com/flutter/skills --skill flutter-animating-apps