Flutter Animation
This is the most important concept in Flutter. When you tap on a button or go from one page to another page the movements all are animations. Animations increase user experiences and the applications become more interactive.
Flutter provides awesome support for animation and we can separate it into two types as given below:
- Tween Animation
- Physics-based Animation
Tween Animation
It’s a short form for in-betweening. It is to define the start and endpoint of animation on screen. Animation begins at the start value, and completes at the end value. It provides the timeline and curve also, we can define the time and speed of transition. It provides a calculation of the transition between the start and endpoint.
Example
ColorTween { begin: color.green, end: color.blue, }
Physics-based Animation
This type of animation allows you to make an interaction with the app feel realistic and interactive. This animation simulates real-world movements, such as to animate a widget like spring, falling, or swinging which feels like gravity. Thus, it is used to animate the responses to input/movement. An example is time of a flight, and the distance covered which will be calculated according to laws of physics.
Flutter provides two techniques for physics based animation. Which are:
- Implicit Animation
- Explicit Animation
The following figure shows the animation hierarchy in Flutter.
Now, we are going to learn how to create explicit animation in Flutter. There are mainly three types of an animation, which are given below:
- Ticker
- Animation Class
- AnimationController
Ticker
The Ticker class sends a signal at a regular interval, i.e., around 60 times per second. You can understand it by looking at your watch, which ticks at a regular interval. At every tick, It provides a callback method with duration since the first ticks at every second, after starting.
Animation
The Animation class is a core building block of flutter animation. This is nothing else, but it represents a value of a specific type that can change over the lifetime of animation. In Flutter, the widgets that can be animated take an animation object in its parameter. This Animation object provides the information which it reads as the current value of the animation and to which it listens for changes in the values. It has two methods addListener() and addStatusListener(). When any value changes it notifies its listeners added using addListener(). Again, when the status value changes it notifies its listeners added using addStatusListener().
The most common Animation classes are:
- Animation
: It moves values between two decimal numbers over a certain duration. - Animation
: It moves colors between two color values. - Animation
: It imoves sizes between two size values.
Animation Controller
The animation controller allows us to control the animation of the widget. It generates new values whenever the widget is rebuilt and is ready for a new frame. For example, it helps control the start, stop, forward, or repeat of an animation. Once we created the animation controller, we can start building animations based on it, such as a reverse and a curved animation.
Syntax
Step: 1 animationController = AnimationController(vsync: this, duration: Duration(milliseconds: 2500));
Here, we need a vsync and the duration denotes the duration of the animation.
Let’s check an example to learn how to implement them
import 'package:flutter/animation.dart'; import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Animation', theme: ThemeData( // This is the theme of your application. primarySwatch: Colors.blue, ), home: MyHomePage(), ); } } class MyHomePage extends StatefulWidget { _HomePageState createState() => _HomePageState(); } class _HomePageState extends Statewith SingleTickerProviderStateMixin { Animation animation; AnimationController animationController; @override void initState() { super.initState(); animationController = AnimationController(vsync: this, duration: Duration(milliseconds: 2500)); animation = Tween (begin: 0.0, end: 1.0).animate(animationController); animation.addListener((){ setState((){ print (animation.value.toString()); }); }); animation.addStatusListener((status){ if(status == AnimationStatus.completed){ animationController.reverse(); } else if(status == AnimationStatus.dismissed) { animationController.forward(); } }); animationController.forward(); } @override Widget build(BuildContext context) { return Center( child: AnimatedLogo( animation: animation, ) ); } } class AnimatedLogo extends AnimatedWidget { final Tween _sizeAnimation = Tween (begin: 0.0, end: 500.0); AnimatedLogo({Key key, Animation animation}):super(key: key, listenable: animation); @override Widget build(BuildContext context) { final Animation animation = listenable; return Transform.scale( scale: _sizeAnimation.evaluate(animation), child: FlutterLogo(), ); } }
Output
When you run the application in Android Studio, you will get the output. In the screen, you will see that the Flutter logo scaling in forward and reverse direction.
Curved Animation
The curved animation is useful to apply a non-linear curve on the animation object. Thus, the animation’s progress is a curve.
Syntax:
Step: 1 CurvedAnimation(parent: animationController, curve: Curves.bounceOut));
Let us understand it with the previous example by making some changes.
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Application', theme: ThemeData( primarySwatch: Colors.orange, ), home: HeroAnimation(title: 'Hero Animation'), ); } } class HeroAnimation extends StatefulWidget { HeroAnimation({Key key, this.title}) : super(key: key); final String title; @override _HeroAnimationState createState() => _HeroAnimationState(); } class _HeroAnimationState extends State{ Widget _greenRectangle() { return Container( width: 75, height: 75, color: Colors.green, ); } Widget _detailPageRectangle() { return Container( width: 150, height: 150, color: Colors.red, ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: buildDemoWidget(context), ); } Widget buildDemoWidget(BuildContext context) { return Center( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( height: 30.0, ), ListTile( leading: GestureDetector( child: Hero( tag: 'hero-rectangle', child: _greenRectangle(), ), onTap: () => _gotoDetailsPage(context), ), title: Text('Tap on the green icon rectangle to analyse hero animation transition.'), ), ], ), ); } void _gotoDetailsPage(BuildContext context) { Navigator.of(context).push(MaterialPageRoute( builder: (ctx) => Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Hero( tag: 'hero-rectangle', child: _detailPageRectangle(), ), Text('This is a place where you can see details about the icon tapped at previous page.'), ], ), ), ), )); } }
Output

