Flutter Animation has Never Been Easier — Part 1

MELLATI Fatah
Flutter Community
Published in
11 min readMar 14, 2019

--

Introduction

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.

Animator

In my last article, I introduced the states_rebuilder library.

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.

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

Implicit-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 that makes and shapes 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:

I.1- Tween<double>

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.

GIF 1 : Different types of Opacity animation

1- Opacity widget. Default animation:

Default Opacity Animation. You can’t see the animation in the GIF because duration is short and is consumed during the route transition 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.

repeat the animation 5 times

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.

Infinitely repeat animation

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.

Cycle animation 10 times ( animation goes back and forth 5 times)

To infinitely cycle the animation put 0 in the cycles parameter.

Infinitely cycle animation

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.

Opacity animation with FadeTransition 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 FadeTransition.

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.

To avoid widget rebuild each frame, declare it outside the Animator widget

3- FadeTransiton widget. Changing duration:

The default duration is 500ms. You can customize this parameter to the duration you want your animation to take.

Animating opacity with FadeTransition. Changing duration to 2s

4- FadeTransiton widget. Changing Curve:

You can change the default Curve with the help of the curve parameter of the Animator widget.

Animating opacity with FadeTransition. Changing curve to Curves.elasticOut

b- Rotation animation:

GIF 12 : Different types of Rotation animation

1- Rotation around the center:

With Tween<double>, we can easily rotate widgets with Animator. You have three widgets to animate rotation:

1- Transform.rotate widget;
2- Transform widget,
3- RotationTransition widget.

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.

Rotation animation using the Transform.rotate widget

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.

Rotation animation using the Transform widget

The third widget is the RotationTransition widget. It takes an Animation<double> type value for the turn argument to indicate the number of turns.

Rotation animation using the RotationTransition widget

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.

Rotation animation. Changing 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.

Rotation Animation changing the origin of rotation using the alignment argument
Rotation Animation changing the origin of rotation using the origin argument

4- Rotation animation with Transform.rotate. Changing curves

The forth row in the GIF gives you a feeling of Curves.elasticOut, Curves.elasticIn, Curves.elasticInOut and Curves.bounceOut.

Rotation animation. Changing the Curves

c- Scale, SizeTransition and skew animation:

GIF 3: Different types of 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
Scale animation using SizedBox
  • Transform.scale widget;
Scale animation using Transform.scale
  • Transform widget. transform argument of Transform widget takes Matrix4.diagonal3Values(x,y,z). We are animation the x and y not the z component.
Scale animation using Transform
  • ScaleTranstion widget.
Scale animation using ScaleTransition

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:

Scale animation. Changing the origin of scaling with the help of alignment argument
Scale animation. Changing the origin of scaling with the help of origin argument

3- Scale animation using Transform.scale widget. Changing curves:

Scale animation. Changing curves

4- SizeTransition animation

SizeTransition animates its own width (or height) to clip its child horizontally (or vertically).

SizeTransition. the default axis of transition is vertical
SizeTransition. changing the axis of transition direction

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)

SizeTransition. Shifting the axis of transition to the start (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).

SizeTransition. Shifting the axis of transition to the end(the right when TextDirection.ltr, and on the left when TextDirection.rtl)

5- Skew animation:

A Skew animation allows you to tilt the child in one direction while keeping the sides parallel.

Skew animation. The x direction
Skew animation. Both x and y directions

I.2- Tween<Offset> : Translation Animation

GIF 4: Different types of Translation animation

1- Offset Translation:

Tween<Offset> is used to animate translation. There are four widgets used to animate translation:

  • FractionalTranslation widget:
    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).
Translation animation using FractionalTranslation. form minus the width of the child to the plus the width of the child
  • Transform.translate widget:
    The offset argument specifies the translation in pixels.
Translation animation using Transform.translate.
  • SlideTransition widget:
Translation animation using SlideTransition
  • Transform widget
Translation animation using Transform widget. horizontal translation form -50 to +50 pixels
Translation animation using Transform widget. horizontal translation form -50 to +100 pixels

For most practical cases animate translation with FractionalTranslation widget is the best choice.

3- Changing the direction of translation:

Translation animation form (-0.5,-0.5) to (0.5,0.5)
Translation animation form (0,-0.5) to (0,0.5)

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>.

Combining translation and rotation animation using Transform Widget
Combining translation, rotation and scaling animation using Transform Widget

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:

GIF 5: Multi tweens animation

If your animation needs to use multi tweens with different type, Animator has a very easy solution. tweenMap and builderMap argument of Animator are the solution.

1- Two tweens: Opacity + Translation:

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.

The 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:

Three tweens: Opacity + Translation + Rotation

3- Four tweens: Opacity + Translation + Rotation + Color:

4- Five tweens: Opacity + Translation + Rotation + Color + Scaling:

Conclusion:

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.

--

--