flutter_animation_basics
Flutter - Animation Basics
Section titled “Flutter - Animation Basics”Animations enhance user experience by providing visual feedback, guiding focus, and creating a more dynamic and engaging interface. Flutter provides a robust and flexible animation system that allows for both simple pre-canned animations and complex custom animations.
Core Animation Concepts
Section titled “Core Animation Concepts”Flutter’s animation system is built around these core ideas:
- Animation
: The central class representing an animation value of typeT(commonlydouble, but can beColor,Size, etc.). It knows the current value of the animation but not the state of the UI or what’s being animated. Its value can change over time. - AnimationController: Manages the animation playback. It’s a special
Animation<double>that generates values from 0.0 to 1.0 over a specifiedduration. It lets you start (forward()), stop (stop()), reverse (reverse()), and track the animation’s status (AnimationStatus: dismissed, forward, reverse, completed). Requires aTickerProvider(vsync). - TickerProvider (
vsync): ProvidesTickerobjects. Tickers signal when a new frame should be rendered, synchronizing the animation with the screen refresh rate.Stateobjects ofStatefulWidgets can implementTickerProviderStateMixinto act as avsync. - Tween
: Defines the mapping between theAnimationController’s 0.0-1.0 range and the actual range of values needed for the UI property (e.g., size from 50 to 150, color from red to blue). It doesn’t store state; it just defines the interpolationbeginandendvalues. - Curve: Modifies the rate of change of an animation, making it non-linear (e.g., easing in, bouncing out). Applied to an
AnimationControllerusingCurvedAnimation.
Animation Workflow
Section titled “Animation Workflow”The general process for creating explicit animations (where you manage the controller) involves:
- Create an
AnimationController: Usually within theinitStateof aStatefulWidget. Requiresdurationandvsync(provided byTickerProviderStateMixin). - Create a
Tween: Define the beginning and end values for the property you want to animate. - Combine Controller and Tween: Use the
Tween.animate()method, passing theAnimationController(or aCurvedAnimationwrapping the controller) to create anAnimation<T>object. This object will produce the interpolated values. - Listen for Value Changes: Add a listener to the
Animationobject usingaddListener(). Inside the listener, callsetState({})to trigger a rebuild of the widget whenever the animation value changes. - Use the Animation Value: In the
buildmethod, use theanimation.valueto set the property of the widget you are animating (e.g.,width: sizeAnimation.value,color: colorAnimation.value). - Start the Animation: Call methods like
controller.forward(),controller.repeat(), etc. - Dispose the Controller: Crucially, dispose of the
AnimationControllerin theState’sdisposemethod to prevent resource leaks.
Simplifying with AnimatedWidget and AnimatedBuilder
Section titled “Simplifying with AnimatedWidget and AnimatedBuilder”Manually calling addListener and setState can be verbose. Flutter provides helper widgets:
AnimatedWidget: A base class for widgets that animate based on a givenAnimation. You extendAnimatedWidget, pass theAnimationto its constructor’ssuper(listenable: animation), and directly use theanimation.valuein thebuildmethod without needingaddListenerorsetState. Useful for creating reusable animation widgets.AnimatedBuilder: A more general-purpose widget for building animations. It takes ananimationand abuilderfunction. Thebuilderfunction receives theBuildContextand an optionalchildwidget.AnimatedBuilderlistens to the animation and calls thebuilderfunction on every frame tick. It’s efficient because it only rebuilds the part of the widget tree returned by thebuilder, not necessarily the entire widget containing the builder. It’s often preferred overAnimatedWidgetfor specific, non-reusable animations within a larger build method.
Example using AnimatedBuilder (Fade Animation)
Section titled “Example using AnimatedBuilder (Fade Animation)”import 'package:flutter/material.dart';
class FadeLogo extends StatefulWidget { const FadeLogo({Key? key}) : super(key: key);
@override _FadeLogoState createState() => _FadeLogoState();}
// Need TickerProviderStateMixin for vsyncclass _FadeLogoState extends State<FadeLogo> with TickerProviderStateMixin { late AnimationController _controller; late Animation<double> _opacityAnimation;
@override void initState() { super.initState(); _controller = AnimationController( duration: const Duration(seconds: 2), vsync: this, );
// Create a Tween for opacity (0.0 to 1.0) final opacityTween = Tween<double>(begin: 0.0, end: 1.0);
// Option 1: Linear animation // _opacityAnimation = opacityTween.animate(_controller);
// Option 2: Curved animation _opacityAnimation = opacityTween.animate( CurvedAnimation(parent: _controller, curve: Curves.easeIn) );
// Start the animation _controller.forward();
// Optional: Make it repeat // _controller.repeat(reverse: true); }
@override void dispose() { _controller.dispose(); // IMPORTANT: Dispose controller super.dispose(); }
@override Widget build(BuildContext context) { return Center( child: AnimatedBuilder( animation: _opacityAnimation, // Listen to this animation builder: (context, child) { // This builder function runs on every animation tick return Opacity( opacity: _opacityAnimation.value, // Use the current animation value child: child, // Pass the child widget through ); }, child: const FlutterLogo(size: 150), // The widget being animated (passed to builder) ), ); }}
// --- Usage Example ---// void main() => runApp(MaterialApp(home: Scaffold(body: FadeLogo())));Implicit Animations
Section titled “Implicit Animations”For simpler animations where you want to animate a property change over a duration, Flutter provides Implicitly Animated Widgets. These widgets automatically animate changes to their properties.
Examples include:
AnimatedContainer: Animates changes to itswidth,height,color,padding,margin,decoration,transform, etc.AnimatedOpacity: Animates changes to itsopacity.AnimatedPositioned: Animates changes to its position within aStack.AnimatedPadding: Animates changes to itspadding.AnimatedTheme: Animates theme changes.AnimatedDefaultTextStyle: Animates changes to the default text style.
You simply change the target property value within a setState call, and the widget handles the animation controller and tweening internally.
Example using AnimatedContainer
Section titled “Example using AnimatedContainer”import 'package:flutter/material.dart';import 'dart:math';
class AnimatedBox extends StatefulWidget { const AnimatedBox({Key? key}) : super(key: key);
@override _AnimatedBoxState createState() => _AnimatedBoxState();}
class _AnimatedBoxState extends State<AnimatedBox> { double _width = 100.0; double _height = 100.0; Color _color = Colors.blue; BorderRadiusGeometry _borderRadius = BorderRadius.circular(8.0);
void _animateBox() { setState(() { final random = Random(); _width = random.nextDouble() * 200 + 50; // Random width 50-250 _height = random.nextDouble() * 200 + 50; // Random height 50-250 _color = Color.fromRGBO( random.nextInt(256), random.nextInt(256), random.nextInt(256), 1, ); _borderRadius = BorderRadius.circular(random.nextDouble() * 50); }); }
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Implicit Animation')), body: Center( child: AnimatedContainer( // Provide the properties that should be animated width: _width, height: _height, decoration: BoxDecoration( color: _color, borderRadius: _borderRadius, ), // Specify the duration and curve for the animation duration: const Duration(seconds: 1), curve: Curves.fastOutSlowIn, // Example curve child: Center(child: Text('Animate Me!', style: TextStyle(color: Colors.white))), ), ), floatingActionButton: FloatingActionButton( onPressed: _animateBox, child: const Icon(Icons.play_arrow), ), ); }}
// --- Usage Example ---// void main() => runApp(MaterialApp(home: AnimatedBox()));Implicit animations are great for simple, state-driven UI transitions without the boilerplate of explicit animation controllers.
Choosing the Right Animation Type
Section titled “Choosing the Right Animation Type”- Use Implicit Animations for straightforward property changes triggered by state updates.
- Use Explicit Animations (with
AnimatedBuilderorAnimatedWidget) for more complex sequences, repeatable animations, fine-grained control over playback, or when animating properties not covered by implicit widgets.
Flutter’s animation system is powerful. Explore the extensive documentation and examples on flutter.dev to learn about physics-based animations, staggered animations, hero animations (page transitions), and more.