In this video, you are going to take a look at:
- How to use AnimatedContainer to gradually change values over time
- How to use AnimatedCrossFade to cross-fade between two children widgets
- How to use AnimatedOpacity to show or hide widget visibility by animated
fading over time - How to use AnimatedSize to animate the size of a widget
- How to use AnimatedPositioned to animate the position of a widget in a Stack
Flutter has two types of animation: physics-based and Tween. This video will focus on Tween animations.
Tween is short for “in-between,” meaning that the animation has beginning and ending points, a timeline, and a curve that specifies the timing and speed of the transition. The beauty is that the framework automatically calculates the transition from the beginning to end point.
AnimatedContainter
The AnimatedContainter is a Container widget that gradually changes values over a period of time. The AnimatedContainer constructor has arguments called duration, curve, color, height, width, child, decoration, transform, and many others.
How It Works
The AnimatedContainer constructor takes a duration argument, and you use the Duration class to specify 500 milliseconds. The curve argument gives the animation a spring effect by using Curves.elasticOut. The onPressed argument calls the _increaseWidth() method to change the _width variable dynamically. The setState() method notifies the Flutter framework that the internal state of the object changed and causes the framework to schedule a build for this State object. The AnimatedContainer widget automatically animates between the old _width value and the new _width value.
double _height = 100.0; double _width = 100.0; void _increaseWidth() { setState(() { _width = _width >= 320.0 ? 100.0 : _width += 50.0; }); } AnimatedContainer( duration: Duration(milliseconds: 500), curve: Curves.elasticOut, color: Colors.amber, height: _height, width: _width, child: FlatButton( child: Text('Tap to\nGrow Width\n$_width'), onPressed: () { _increaseWidth(); }, ), ),
AnimatedCrossFade
The AnimatedCrossFade widget provides a great cross-fade between two children widgets. The AnimatedCrossFade constructor takes duration, firstChild, secondChild, crossFadeState, sizeCurve, and many other arguments.
How It Works
The AnimatedCrossFade constructor takes a duration argument, and you use the Duration class to specify 500 milliseconds. The sizeCurve argument gives the animation between the two children’s size a spring effect by using Curves.bounceOut. The crossFadeState argument sets the child widget to be shown once the animation is completed. By using the _crossFadeStateShowFirst variable, the correct crossFadeState child is displayed. The firstChild and secondChild arguments hold the two widgets to animate.
bool _crossFadeStateShowFirst = true; void _crossFade() { setState(() { _crossFadeStateShowFirst = _crossFadeStateShowFirst ? false : true; }); } AnimatedCrossFade( duration: Duration(milliseconds: 500), sizeCurve: Curves.bounceOut, crossFadeState: _crossFadeStateShowFirst ? CrossFadeState.showFirst : CrossFadeState.showSecond, firstChild: Container( color: Colors.amber, height: 100.0, width: 100.0, ), secondChild: Container( color: Colors.lime, height: 200.0, width: 200.0, ), ),
AnimatedOpacity
If you need to hide or partially hide a widget, AnimatedOpacity is a great way to animate fading over time. The AnimatedOpacity constructor the takes duration, opacity, curve, and child arguments. For this example, you do not use a curve; since you want a smooth fade-out and fade-in, it’s not necessary.
How It Works
The AnimatedOpacity widget takes a duration parameter, and you use the Duration class to specify 500 milliseconds. The opacity parameter is a value from 0.0 to 1.0. The opacity value of 1.0 is fully visible, and as the value changes toward zero, it starts to fade away. Once it reaches zero, it’s invisible.
double _opacity = 1.0; void _animatedOpacity() { setState(() { _opacity = _opacity == 1.0 ? 0.3 : 1.0; }); } AnimatedOpacity( duration: Duration(milliseconds: 500), opacity: _opacity, child: Container( color: Colors.amber, height: 100.0, width: 100.0, child: FlatButton( child: Text('Tap to Fade'), onPressed: () { _animatedOpacity(); }, ), ), ),
AnimatedSize
If you need to animate the size of a widget, you can use the AnimatedSize to increase or decrease the child’s widget size over a given duration. The AnimatedSize constructor takes the duration, vsync, curve and child arguments.
How It Works
The AnimatedSize widget takes a duration parameter, and you use the Duration class to specify 1 second. The vsync is referenced by this, meaning this reference of the _AnimatedSizeWidgetState class. The curve argument gives the animation a spring effect by using Curves.easeInOut. The child Icon size property takes the _size variable and as it changes the new size is animated.
Note in order to use the vsync property you use the SingleTickerProviderStateMixin class.
class _AnimatedSizeWidgetState extends State<AnimatedSizeWidget> with SingleTickerProviderStateMixin { double _size = 100.0; void _increaseWidth() { setState(() { _size = _size >= 300.0 ? 100.0 : _size += 100.0; }); } @override Widget build(BuildContext context) { return Row( children: <Widget>[ AnimatedSize( duration: Duration(seconds: 1), vsync: this, child: FlatButton( child: Icon( Icons.cake, size: _size, color: Colors.orange, ), onPressed: () { _increaseWidth(); }, ), ), ], ); } }
AnimatedPositioned
If you need to animate the position of a widget in a Stack, you can use the AnimatedPositioned to animate the position of the child widget.
How It Works
The AnimatedPositioned widget takes a duration parameter, and you use the Duration class to specify 2 seconds. The child Icon left property takes the _left variable and as it changes the new position within the Stack is animated.
double _left = 0.0; void _increaseWidth() { setState(() { _left = _left >= 300.0 ? 0.0 : _left += 100.0; }); } GestureDetector( child: Stack( fit: StackFit.expand, children: <Widget>[ AnimatedPositioned( child: Icon( Icons.free_breakfast, size: 128.0, color: Colors.amber, ), duration: Duration(seconds: 2), left: _left, curve: Curves.elasticOut, ), ], ), onTap: () { _increaseWidth(); }, );