This tutorial shows you how to create animation using AnimatedBuilder
in Flutter.
Flutter framework is known to be very good in terms of animation support. One of the useful widgets for creating animation is AnimatedBuilder
. It works by listening to a Listenable
(usually an AnimationController
and call a builder function each time the animation changes value. How to use the widget? Find out in this tutorial.
Using AnimatedBuilder
Below is the constructor of AnimatedBuilder
.
const AnimatedBuilder({
Key key,
@required Listenable animation,
@required this.builder,
this.child,
})
To use AnimatedBuilder
, there are two required named arguments you have to pass. The first one is animation
whose type is Listenable
. To provide the value, we can pass an instance of Animation
class, which extends Listenable
. The most common way to create an Animation
is by using AnimationController
. That means the AnimatedBuilder
listens to the passed AnimationController
for value changes.
The constructor of AnimationController
requires you to pass a named argument vsync
whose type is TickerProvider
. To obtain the TickerProvider
, you can add with TickerProviderStateMixin
on your State
class.
Below is an example of how to create an AnimationController
. The AnimationController
is stored in a state variable _controller
. Because the class already uses TickerProviderStateMixin
, you can use this
keyword to obtain the TickerProvider
. The animation duration in the example below is set to 5 seconds which means a full animation needs 5 seconds to complete. The created animation must be triggered to be run, for example by using forward()
, reverse()
, or repeat()
. Another thing you need to do is override dispose()
method so that you can dispose the controller.
class _AnimatedWidgetExampleState extends State<_AnimatedWidgetExample> with TickerProviderStateMixin {
late AnimationController _controller;
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 5),
vsync: this,
)..repeat();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Woolha.com Flutter Tutorial'),
),
body: Center(
child: Container(),
),
);
}
}
Another required named argument is builder
. The value you need to pass is a function with two parameters whose type in order are BuildContext
and Widget
. Every time the controller changes value, Flutter calls the builder function. The Widget
defined as the child of the AnimatedBuilder
will be passed as the second argument. The function needs to return a Widget
. For example, you can use Transform
to apply transformation to the child
based on the current value of the controller.
Because the builder function is called at every animation tick, it can be inefficient if the builder
returns a subtree that doesn't depend on the animation. For that case, Flutter recommends us to pre-built that subtree by passing it as the child
argument which will be passed to the builder
function.
AnimatedBuilder(
animation: _controller,
child: Container(
width: 200.0,
height: 200.0,
color: Colors.teal,
child: const Center(
child: Text(
'Woolha.com',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 24,
),
),
),
),
builder: (BuildContext context, Widget? child) {
return Transform.rotate(
angle: _controller.value * 2 * math.pi,
child: child,
);
},
)
Output:
Full Code
Below is the full code of this tutorial.
import 'dart:math' as math;
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Woolha.com Flutter Tutorial',
home: _AnimatedWidgetExample(),
);
}
}
class _AnimatedWidgetExample extends StatefulWidget {
@override
State<StatefulWidget> createState() => new _AnimatedWidgetExampleState();
}
class _AnimatedWidgetExampleState extends State<_AnimatedWidgetExample> with TickerProviderStateMixin {
late AnimationController _controller;
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 5),
vsync: this,
)..repeat();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Woolha.com Flutter Tutorial'),
),
body: Center(
child: AnimatedBuilder(
animation: _controller,
child: Container(
width: 200.0,
height: 200.0,
color: Colors.teal,
child: const Center(
child: Text(
'Woolha.com',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 24,
),
),
),
),
builder: (BuildContext context, Widget? child) {
return Transform.rotate(
angle: _controller.value * 2 * math.pi,
child: child,
);
},
),
),
);
}
}
AnimatedBuilder
Parameters
Key key
: This widget's key.Listenable animation
*: AListenable
that this widget listens to.TransitionBuilder builder
*: A callback called every time the animation changes value.Widget child
: The widget to be passed to thebuilder
.
*: required
Another alternative to this widget is AnimatedWidget
, which rebuilds when its Listenable
changes value .