Flutter Animation has Never Been Easier — Part 1
Adding animations to your app is an important part in the app development lifetime. Animation is used to add visual effects to notify users that some part of the app’s state has changed. It gives your app a polished look that witnesses the quality of your app to the end users.
Flutter has a very good animation library. Many articles have been written to explain the different parts of the Flutter animation library. In this article, I propose a new package that makes animation in Flutter as easy as the simplest widget in Flutter.
In my last article, I introduced the states_rebuilder library.
states_rebuilder Flutter and Dart package - a simple yet powerful state management technique for Flutterpub.dartlang.org
It is so an easy and so an effective state management technique, that I changed the way I look to animation in Flutter. I gathered my ideas on animation and created a new package which I called ANIMATOR.
animator Flutter and Dart package - A Flutter library that makes animation easer. It allows for separation of animation…pub.dartlang.org
Flutter create with states_rebuilder and animator:
The main challenge of Flutter Create is to build something interesting, inspiring, and beautiful with Flutter using 5KB dart code. states_rebuilder and animator helps you reduce the amount of dart code in your app, especially if your app has many statefullWidgets and animations.
Take this example Form flutter documentation website/examples/animation/animate3/lib/main.dart. It has 60 lines and 1.63 KB.
With animator it looks like this:
It has 21 lines and 0.58 KB which corresponds to 64% reduction of code size. The more your app has statefullWidgets and animations the more you gain in code size.
Let’s see what animator offers and how it animates widgets.
In flutter animation can be classified:
- Implicit: such as AnimatedContaine, AnimatedPadding, AnimatedPositioned and AnimatedDefaultTextStyle.
- Explicit: Where you define AnimationController, Animation and Tween classes, and you should explicitly start, stop and listen to animation status.
Following the same fashion, the Animator package offers implicit-like and explicit-like animation
In Animator animation is nothing than:
1- Two values where the animation value changes between them. This is defined by Tween class;
2- The duration the animation takes. This is defined by Duration class;
3- The path or curve to define how the animation varies between the begin value and the end value. This is defined by Curves class;
4- The ability to control how many times the animation repeats, cycle back and forth, and when to stop it. This is defined by the repeats and cycles parameter of the Animator class;
5- The product of an Animation is an animation value which you can use to update the UI in each frame of the animation.
The figure bellow, sketches the above points, where:
- INPUT = points 1,2 &3;
- CONTROL = point 4 ; and
- OUTPUT = point 5.
If I were to resume animation with Animator in one word, I would say TWEENs. Yes, the only part the make and shape your animation is Tween. In the remainder of this article and the next ones, I will go through all the available Tweens in Flutter and show you what can do with them.
I- One Tween Animation:
a - Opacity animation:
The simplest and the most used Tween is the Tween<double>. Animation Opacity is a good starting point to dive into Animator. The GIF bellow shows different opacity animations that we will reproduce in the next couple of paragraphs.
1- Opacity widget. Default animation:
After importing Animator, in the builder parameter of the Animator widget, you define the Opacity widget with opacity= anim.value. That’s all to animation the Opacity with the default animation. Default animation is:
- tween = Tween<double>(begin:0 , end:1);
- duration = Duration(miliseconds : 500); and
- curve= Curves.linear
The animation starts automatically when the widget is rendered, and lasts only for one forward path (from beginning to the end). When animation is completed, it stops and the
AnimationController is disposed to free resources.
With repeat parameter, you can define the number of repeats you want your animation to do before stopping it.
repeats : 5 , means that animation goes from beginning to end and restart from the beginning five times before stopping and disposing AnimationController.
To infinitely repeat the animation put 0 in the repeats parameter.
If you want your animation to go both paths, forward and backward, use cycles parameter.
cycles = 2 (or 2 x 1), means that the animation goes forward and backward one time and stop at the beginning.
cycles = 3 (or 2 x 1+1), means that the animation goes forward then backward then forward again and stop at the end.
cycles= 10 (or 2 x 5), means that the animation goes forward and backward five times and stop at the beginning.
To infinitely cycle the animation put 0 in the cycles parameter.
2- FadeTransiton widget. Default animation:
Flutter has many ready to use widgets for animation. With Animator you can make profit of these widgets.
FadeTransition animates the opacity of a widget.
It’s important to note that opacity argument of
FadeTransition takes Animation type value not a double value as we are used to with Opacity widget.
We can use repeats and cycles parameter of Animator to control the number of repeats and cycles the animation should take before stopping.
The first and second rows of the opacity GIF above show the same behavior although the first use Opacity and the second uses
Animating opacity with Opacity widget and with
FastTransition result in the same visual effect, but for performance considerations, the use of
FaseTransition is preferred.
To avoid that animated widget (and possibly its subtree) from rebuilding each frame, you can store the widget in a final variable outside the Animator widget and use that variable in the builder argument of the Animator.
3- FadeTransiton widget. Changing duration:
The default duration is 500ms. You can customize this parameter to the duration you want your animation to take.
4- FadeTransiton widget. Changing Curve:
You can change the default Curve with the help of the curve parameter of the Animator widget.
b- Rotation animation:
1- Rotation around the center:
With Tween<double>, we can easily rotate widgets with Animator. You have three widgets to animate rotation:
The first widget is Transform.rotate which takes a double value for the angle argument. the Tween with 0 and ends with 2*pi to complete one turn. The default origin of rotation is the center.
The second widget is the Transform widget which takes a
Matrix4.rotationZ(anim.value) in the transform argument. You have to explicitly specify the alignment argument to be Alignment.center to center the origin of rotation.
The third widget is the
RotationTransition widget. It takes an
Animation<double> type value for the turn argument to indicate the number of turns.
The three above widget reproduce the same animation effect.
2- Rotation around X, Y and Z axis using the Transform Widget
Transform widget is most suitable when you want to change the axis of rotation.
3- Changing the origin of rotation using the Transform.rotate widget
In most cases where you want to rotate around the Z axis of the widget, use Transform.rotate. You have the ability to change the origin of rotation with the help of alignment and origin arguments.
4- Rotation animation with Transform.rotate. Changing curves
The forth row in the GIF gives you a feeling of
c- Scale, SizeTransition and skew animation:
1- Scale from center:
Scale animation is achieved by:
- Directly by animating the width and height of SizedBox widget; the default Tween<double>(begin:0, end:1) is used
- Transform.scale widget;
- Transform widget. transform argument of Transform widget takes
Matrix4.diagonal3Values(x,y,z). We are animation the x and y not the z component.
- ScaleTranstion widget.
For most practical cases animating the scale with Transform.scale is the best choice.
2- Changing the origin of scaling using the Transform.scale widget:
3- Scale animation using Transform.scale widget. Changing curves:
4- SizeTransition animation
SizeTransition animates its own width (or height) to clip its child horizontally (or vertically).
We can change the axis of transition (the axis that sizeFactor is modifying it).
axisAlignment argument takes a double value. A value of -1 shifts the axis of transition to start when axis argument is Axis.horizontal (-1 indicates the top when axis is Axis.vertical).
The start is (the left when TextDirection.ltr, and on the right when TextDirection.rtl)
A value of 1 shifts the axis of transition to end when axis argument is Axis.horizontal (1 indicates the bottom when axis is Axis.vertical).
5- Skew animation:
A Skew animation allows you to tilt the child in one direction while keeping the sides parallel.
I.2- Tween<Offset> : Translation Animation
1- Offset Translation:
Tween<Offset> is used to animate translation. There are four widgets used to animate translation:
The translation is expressed as a Offset scaled to the child’s size. For example, an Offset with a dx of 1 (or -1) will result in a horizontal translation equals to the width of the child (or equals to minus the width of the child).
- Transform.translate widget:
The offset argument specifies the translation in pixels.
- SlideTransition widget:
- Transform widget
For most practical cases animate translation with
FractionalTranslation widget is the best choice.
3- Changing the direction of translation:
4- Translation animation. Changing curves:
5- Translation animation using Transform widget. combining multiple animation
With the default Transform constructor you can combine rotation, scale and translate and many other type of animation with one Tween<double>.
That’s enough for one tween animation for the article. In the next article I will go through: IntTween, StepTween, AlignmentTween, AlignmentGeometryTween, EdgeInsetsTween , EdgeInsetsGeometryTween, FractionalOffsetTween, BorderTween, BorderRadiusTween, ShapeBorderTween, DecorationTween, BoxConstraintsTween, RectTween, TextStyleTween and ThemeDataTween.
I- Multi Tweens Animation:
If your animation needs to use multi tweens with different type, Animator has a very easy solution.
builderMap argument of Animator are the solution.
1- Two tweens: Opacity + Translation:
tweenMap argument is a Map<String, Tween>. Keys are your name of the animation, and values are
Tweens of any type.
builderMap is of type Function(Map<String, Animation>) -> Widget. Wherever you want a particular type of animation, use the corresponding key to call it.
There is no limit on the number of Tweens to use.
2 - Three tweens: Opacity + Translation + Rotation:
3- Four tweens: Opacity + Translation + Rotation + Color:
4- Five tweens: Opacity + Translation + Rotation + Color + Scaling:
Animator has an argument called endAnimationListener. It takes a
VoidCallback function to be executed when animation is finished. One use of this argument is to trigger another animation once the actual animation is finished. The GIF bellow used this argument to produce a animation of all the animations we covered in this article.
To better see the animation, hit this link.
The source code of this animation is here.