How to Use AnimationController in Flutter: Simple Guide
Use
AnimationController in Flutter by creating it inside a StatefulWidget with a TickerProvider, then start, stop, or reverse the animation using its methods. It controls animation timing and requires disposing to free resources.Syntax
The AnimationController requires a vsync parameter, usually provided by a TickerProvider like SingleTickerProviderStateMixin. You create it with a duration and control the animation with methods like forward(), reverse(), and stop().
- vsync: Prevents offscreen animations from consuming resources.
- duration: Length of the animation.
- forward(): Starts the animation forward.
- reverse(): Runs the animation backward.
- dispose(): Frees resources when done.
dart
class _MyWidgetState extends State<MyWidget> with SingleTickerProviderStateMixin { late AnimationController _controller; @override void initState() { super.initState(); _controller = AnimationController( vsync: this, duration: const Duration(seconds: 2), ); } @override void dispose() { _controller.dispose(); super.dispose(); } }
Example
This example shows a square that grows and shrinks repeatedly using AnimationController. The controller drives the size animation and updates the UI with AnimatedBuilder.
dart
import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp(home: AnimationDemo()); } } class AnimationDemo extends StatefulWidget { const AnimationDemo({super.key}); @override State<AnimationDemo> createState() => _AnimationDemoState(); } class _AnimationDemoState extends State<AnimationDemo> with SingleTickerProviderStateMixin { late AnimationController _controller; @override void initState() { super.initState(); _controller = AnimationController( vsync: this, duration: const Duration(seconds: 2), lowerBound: 50.0, upperBound: 200.0, )..repeat(reverse: true); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('AnimationController Example')), body: Center( child: AnimatedBuilder( animation: _controller, builder: (context, child) { return Container( width: _controller.value, height: _controller.value, color: Colors.blue, ); }, ), ), ); } }
Output
A blue square in the center of the screen smoothly grows from 50x50 to 200x200 pixels and then shrinks back repeatedly.
Common Pitfalls
- Not disposing the
AnimationControllercauses memory leaks. - Forgetting to add
with SingleTickerProviderStateMixinto your state class leads to errors. - Using
AnimationControlleroutside aStatefulWidgetor withoutvsynccauses performance issues. - Not calling
setStateor usingAnimatedBuildermeans UI won't update with animation.
dart
/* Wrong: Missing dispose */ class _WrongState extends State<MyWidget> with SingleTickerProviderStateMixin { late AnimationController _controller; @override void initState() { super.initState(); _controller = AnimationController(vsync: this, duration: Duration(seconds: 1)); _controller.forward(); } // Missing dispose method } /* Right: Proper dispose */ @override void dispose() { _controller.dispose(); super.dispose(); }
Quick Reference
- AnimationController(vsync, duration): Creates the controller.
- forward(): Starts animation forward.
- reverse(): Runs animation backward.
- repeat(reverse: true): Loops animation back and forth.
- dispose(): Clean up controller.
Key Takeaways
Always create AnimationController inside a StatefulWidget with SingleTickerProviderStateMixin for vsync.
Dispose the AnimationController in the dispose() method to avoid memory leaks.
Use methods like forward(), reverse(), and repeat() to control animation playback.
Use AnimatedBuilder or setState to update the UI when the animation value changes.
AnimationController controls timing but needs a widget to show the animation visually.