The opening

Animation plays an important role in APP design. Purposeful and functional animation can not only add aesthetic decoration, but also enable users to get a good experience.

Here is a brief introduction to how animation is used in Flutter and how to choose the animation that fits your needs. We will also analyze how animation is implemented in Flutter with the source code.

Implicit Animaition

introduce

The ImplicitlyAnimatedWidget, as its name implies, is an abstract class for implicit animation in Flutter. There are many subclasses that can be used to animate a Flutter with very little code.

Because it is very simple to use, I will not do too much space to introduce, the following is to say what it has, advantages and disadvantages, and take two subclasses to do some examples.

How implicit animation is implemented will be dissected later in this article.

Implicit animation family

As you can see from the figure above, the ImplicitlyAnimatedWidget has 11 public and two private subclasses. Each of the 11 public subclasses can be used directly to animate and is easy to use.

The advantages and disadvantages

  • advantages

    • Subclass more, that is, animation more
    • Easy to use, easy to get started
    • Less code
  • disadvantages

    • Process out of control
    • It’s simply switching from one state to another
    • Flexibility is poor
    • Unable to listen to the entire animation process

example

Let’s look at a few simple examples of how to use implicit animation

AnimatedContainer

AnimatedContainer has a similar API to Container. You just need to refresh the AnimatedContainer after modifying its properties, and the Widget animates from the old value to the new value.

AnimatedContainer has two more animation-related attributes, Duration and curve, than a regular Container.

Duration Specifies the duration of animation execution.

Curve is an animation curve, which will be explained later.


AnimatedOpacity

AnimatedOpacity also has an API similar to Opacity, which only adds animation-related properties on top of Opacity, such as duration, curve and onEnd. When the Opacity value is changed, the refresh Widget will refresh within a specified time. Animate the transition to the new value.

Duration Specifies the duration of animation execution.

Curve is an animation curve, which will be explained later

OnEnd is the callback to the end of the animation

Many implicitly animated widgets add animation properties to normal widgets.

Container –> AnimatedContainer

Opacity –> AnimatedOpacity

Padding –> AnimatedPadding

Align –> AnimatedAlign

. .

But what if we want to make an implicit animation, but we don’t know which implicit animation Widget to use, or we don’t have an implicit animation Widget that will fit the scene

Omnipotent player in implicit animation: TweenAnimationBuilder

TweenAnimationBuilder can animate everything other Wigdets in the implicit animation family can.

Building a TweenAnimationBuilder requires two necessary parameters:

1, tween: tween

Constructing a Tween takes two arguments

Tween({ this.begin, this.end })

The transition value of the animation is computed between begin and end of the Tween.

Suppose we now want the width of the Widget to be enlarged from 50 to 100. We can build a tween of 50 to 100

Tween(begin: 50, end: 100)

When we build Tween, begin and end accept generic arguments, so Tween can be any type of interval, so Tween can transition between any two values. Flutter also help us to provide better achieve good Tween, such as: ColorTween, SizeTween, BoxConstraintsTween, etc., convenient for us to use.

Build: Widget Function(BuildContext context, T value, Widget child)

A callback function that is called repeatedly during the animation to return widgets that need to be displayed.

Value is the value calculated by tween during the current animation to be displayed.

Color animation

Change from red to blue in three seconds

Size of the animation

100 goes to 300 in three seconds

Animate dimensions, colors, rounded corners simultaneously

Initialize a tween between 0 and 1, and use Color and BorderRadius’s lERP function to calculate the value of the current animation time, increasing the width and height from 200 to 300.

conclusion

Implicit animation is relatively easy to use and get started with. Flutter has already helped us to encapsulate many implicit animation widgets that can be used directly in the scene. If none of these are available, use TweenAnimationBuilder.

But if you encounter complex scenes and want to better control animation, implicit animation is not competent, this time you need to use display animation or lower-level animation to do.

Explicit Animaition

introduce

AnimatedWidget is an abstract class for displaying animations, but it also has many subclasses to help developers quickly animate certain scenes.

The AnimatedWidget receives a Listenable property and listens for the animation. AnimationController inherits from Listenable, and if you pass an AnimationController object to the AnimatedWidget, you can control the animation and listen to the animation.

Display animation family

There are also 11 public classes and 2 private classes for display animation. In addition to AnimatedBuilder, all of the 11 public classes help developers to quickly create animations for specific scenarios.

SizeTransition can be used to animate sizes

ScaleTransition can be used to animate scaling

PositionedTransition can be used to animate positions

. .

AnimationController

AnimationController is an AnimationController that controls and listens to animations.

To initialize an AnimationController, you must pass a parameter called vsync. Vsycn is a parameter of type TickerProvider, which registers and triggers a callback for each frame. We’ll cover TickerProvider later.

If an AnimationController is initialized, it must be disposed manually, otherwise it will leak memory.

AnimationController Controls animation:

Can you control the value from which the animation starts to play forward(from:)

Reverse animation (from:)

Stop animation stop()

Reset animation reset()

What value should the animation play to? AnimateTo (0.7)

And so on.

Monitor animation:

Value of listening:

 // monitor the animation value change process

 // Value ranges from lowerBound to upperBound of the AnimationController

 // The default value is 0.0 to 1.0

animationController.addListener(() {

    print(animationController.value);

});
Copy the code

State monitoring

// To monitor the state of the animation.

// Status is a value of type AnimationStatus. There are four values

animationController.addStatusListener((status) {

    print(status);

});
Copy the code

AnimationStatus

AnimationStatus describe
dismissed The state when controller.value== Controller.lowerbound can also be understood as the state when the controller calls reverse() to perform the animation and the animation completes
forward When the controller calls Forward () to perform the animation, the state of the animation before it completes
reverse When the controller calls Reverse () to perform the animation, the state of the entire animation process before the animation completes
completed Controller.value == controller.upperbound state when the controller calls forward() to perform the animation and the animation is complete

Curve

In the process of animation execution, the animation can have linear, acceleration, deceleration, elasticity and other animation Curve effects.

The following two diagrams show what curve might look like if used in animation.

More Curve effect: API. Flutter. Dev/flutter/ANI…

example

Some conceptual things were introduced above, but here are some examples to give you a quick feel for how an explicit animation is used.

Since initializing an AnimationController requires passing a vsync parameter of type TickerProvider, Flutter already helps us to implement two TickerProviders. SingleTickerProviderStateMixin and TickerProviderStateMixin, we only need will go with the current State to do animation can be used directly.

SingleTickerProviderStateMixin is used in the current State only need a AnimationController, If the current class has more than one AnimationController, you need to mix in TickerProviderStateMixin.

RotationTransition

The core steps of explicit animation:

  1. Define an AnimationController variable
  2. Initialize the animationController at initState() and set the animation duration and vsync.
  3. Assign the animationController to the explicit animation
  4. Execute the animation when it is neededanimationController.forward()Can.
  5. It must be called in the Dispose () methodanimationController.dispose()Otherwise, memory leaks may occur.

In the example above, we use RotationTransition. This explicit Animation Widget rotates, has a turns property of an Animation type, and the AnimationController inherits from the Animation.

All explicitly animated widgets also have a property of type Animation. Different Widget property names are different, but all widgets can receive an AnimationController.

Omnipotent player in explicit animation: AnimatedBuilder

As with implicit animations, sometimes we don’t know what explicit animations are available, or the existing ones don’t fit the scenario. What do we do? There is also an all-rounder in the explicit animation family, AnimatedBuilder.

AnimatedBuilder accepts two required parameters

Listenable animation;

Widget Function(BuildContext context, Widget child) builder;

An animation can assign an AnimationController directly to it

The Builder method needs to return the widgets that need to be displayed during the animation

Basic usage

Code explanation:

In the previous example, we initialized the Controller in initState(), set the animation duration to 2 seconds, and set lowerBound to 100 and upperBound to 200.

When we call Controller.forward (), the Builder function of AnimatedBuilder is called in every frame of the screen refresh, and the value of the Controller increases linearly from 100 to 200 in 2 seconds.

So assigning controller.value to width and height in the Builder will have a magnified animation effect.

Do multiple animations at once

We want to animate multiple things at once, change sizes, change colors, add rounded corners, rotate

Code explanation:

In the example above, what we did was in 2 seconds, the Container went from 100 to 200, red to blue, rounded corners went from 0 to 20, and did a full rotation.

As we can see from the code, we define not only one controller in State, but also three other properties of Animation type, respectively:

SizeAnimation: Used to animate size

DecorationAnimation: Animates colors and rounded corners

RotationAnimation: Used to animate rotations

In addition, the builder function of AnimatedBuilder does not use the controller property, but uses the values of the other three animations. What are these three animations?

In initState(), we first initialize the controller, set the duration to 2 seconds and vsync.

The other three animations are initialized below.

The sizeAnimation is a Tween of 100 to 200, and when you call animate with Tween and pass in controller, an Animation object is returned.

RotationAnimation is similar to sizeAnimation.

DecorationAnimation we can see that it is a DecorationTween. DecorationTween is a class that descends from Tween, and its begin and end elements receive decorations. Because what we’re going to do is we’re going to change the color and the rounded corners, and the BoxDecoration is the inheritance of the Decoration, and the BoxDecoration has the color property and the rounded corners property. So we’re using a DecorationTween here, where we have begin color:red, borderRadius:0 and end color:blue, borderRadius:20, which is red to blue, rounded from 0 to 20.

Why does animation.value create an animation in the Builder?

An animation can be deval Ed in a “_AnimateDeval” manner. In a “_Animatedeval” manner, it holds both Tween and AnimationController variables. So when we use animation.value we’re actually doing some computation.

The call path is shown below:

Note 📢 : The fifth step above is for Tween only. If it is a subclass of Tween, some subclasses override the lerp function, such as DecorationTween, which overrides the lerp function.

Therefore, as the value of the controller changes constantly during the animation process, the value of the animation is also changed in the Builder method of AnimatedBuilder, so the animation effect is generated.

Staggered animation

We sometimes want to have multiple animations, but not all animations are executed together, but in sequence. Dimensions, colors, rounded corners, and rotations should be executed in turn.

Code explanation:

In the example above we can see that the animation is divided into four segments.

  1. Change in size
  2. Color change
  3. Rounded corners change
  4. rotating

As can be seen from the code, this code is 80 or 90 percent the same as the above code that does Animation at the same time, except that one more chain method is called and a CurveTween is passed in when initializing each Animation.

Let’s just look at what chain and CurveTween do here. The rest of the animation steps are exactly the same as above, so we won’t explain it again.

Chain method

The chain method is a method of Animatable, which as its name implies means link, linking multiple Animatable together. Tween inherits Animatable.

We still remember that when calculating animation.value above, one of the steps is to call tween’s transform method. If multiple Tween’s are linked together to create an animation, and then animation.value is called, The tween’s transform is then called to compute the final value.

CurveTween

It’s a Tween that generates an animated curve, so that it can be combined with other Tween’s.

CurveTween({ @required this.curve })

There are no more details about other curves, but they are also introduced above. Here is a Curve with special usage, which is Interval.

Interval(this.begin, this.end, { this.curve = Curves.`` linear ``})

The value of begin to end of Interval ranges from 0 to 1.

It can be used for animation delay.

If we have an 8-second animation that uses Interval, and Interval is between 0.5 and 1, the first 4 seconds of the animation will be useless, the animation will start after 4 seconds, and the last 4 seconds will complete the animation.

If Interval is between 0.25 and 0.5, the animation starts at second 2 and ends at second 4, with all animations completed between second 2 and second 4.

Then we look at the above code, it is not difficult to understand how the four animations are executed.

We have a total of 8 seconds of animation, put the size change animation in the first 2 seconds, the color change animation between 2 and 4 seconds, the rounded corner animation between 4 and 6 seconds, and the rotation animation in the last 2 seconds.

conclusion

Explicit animations are a little more complex than implicit animations, but much more flexible, and AnimatedBuilder should work for all of our explicit animations.

In this section we explain the use of AnimationController. Although we don’t go into all its methods individually, we do explain some of its core methods, some of which can be easily identified by their names.

We also introduced Curve and Interval.

There are also the usage and principle of combination animation and staggered animation.

TickerProvider

TickerProvider is an indispensable class in animation. It builds a Ticker object that can be registered in a SchedulerBinding and trigger a callback for each frame.

The value of the AnimationController is calculated in the callbacks of each frame.

TickerProvider is an abstract class, Flutter has help me to achieve two TickerProvider TickerProviderStateMixin and SingleTickerProviderStateMixin. The performance better than TickerProviderStateMixin SingleTickerProviderStateMixin. When we are in the State of only by a AnimationController is recommended to use SingleTickerProviderStateMixin, and most of the animation scene a AnimationController will have to be able to do.

Let’s take a look at how AnimationController, TickerProvider, and Ticker work together.

TickerProvider is an abstract class with only one instance of createTicker(TickerCallback onTick).

Let’s take a look at is how to implement SingleTickerProviderStateMixin.

Leaving out the comments and debug code, you can see that you simply create a Ticker object and pass the onTick callback to the Ticker object.

After that we will infiltrate into State SingleTickerProviderStateMixin, where the createTicker is called?

The AnimationController initializes an AnimationController by passing in a TickerProvider object. The AnimationController initializes an AnimationController by calling createTicker. The ticker instance created is saved and passed a _tick callback method.

So what does _ticker do? Let’s take a look at what’s going on in Ticker.

Flutter is a callback to animation frames. It does not start by default when a Flutter is initialized. It starts when the start method is called and is driven by a SchedulerBinding.

Start determines whether its state is available. If so, the scheduleTick method is called. ScheduleTick passes the _tick callback to the SchedulerBinding.

SchedulerBinding’s scheduleFrameCallback method calls scheduleFrame and wraps callback into the _FrameCallbackEntry instance. Store the object in the _transientCallbacks callback collection.

Circle in the figure below is _transientCallbacks explanation, said popular point is in front of the frame refresh, will back this collection of all the callback function, used to synchronize the behavior of the application to the system, according to my understanding is that, before the page refreshes the data ready, when refresh with prepare to render the data interface.

Calling scheduleFrame initializes the callback for screen frame refresh and then marks the need to call handleBeginFrame for screen frame refresh

So in the handleBeginFrame method, it’s going to call our Ticker callback function, and when it’s done, it’s going to clear out the collection of callbacks that we saved.

Calling the callback above is equivalent to calling the _tick function of the AnimationController

Here we summarize the main steps:

  1. TickerProvider provides a method createTicker that creates a Ticker object
  2. Pass the TickerProvider to the AnimationController initialization method
  3. When AnimationController is initialized, createTicker of the TickerProvider is called to initialize a Ticker object and a function _tick is passed to the Ticker object
  4. The Ticker object is passed back to the _transientCallbacks callback set in SchedulerBinding when it starts.
  5. The handleBeginFrame function is called when a screen frame is refreshed
  6. All callbacks in _transientCallbacks are called in the handleBeginFrame function
  7. Finally, the _tick function of the AnimationController will be called. The _tick function will calculate the current value of the animation and the state of the animation and inform the listener

The source code parsing

In this section we’ll take a look at the source code for implicit and explicit animations to see how they actually work.

Let’s take a look at the two most versatile widgets in implicit and explicit animation, TweenAnimationBuilder and AnimatedBuilder.

TweenAnimationBuilder

Let’s see how it works, passing in a Tween, passing in a time, passing in a build callback.

The build callback will be called in a second, and the value in the Builder will increase linearly from 0 to 1 in a second.

TweenAnimationBuilder inheritance structure.

The Ticker has the ability to listen for frame refresh, the TickerPorvider has the ability to create a Ticker, and the AnimationController accepts a TickerProvider.

When we use implicit animation, we don’t create the AnimationController at all, so how does it work?

The inheritance diagram above you can see is mixed with the TickerPorvider ImplicitlyAnimatedWidgetState. We came to ImplicitlyAnimatedWidgetState look at the inside.

Founded AnimationController ImplicitlyAnimatedWidgetState

AnimatedWidgetBaseState listens for changes in the value of the AnimationController and then continuously calls setState to refresh itself

Because the parent class calls setState, so _TweenAnimationBuilderState build will be constantly call, and in the build is good computing tween the value of the corresponding to the TweenAnimationBuilder builder callback methods.

TweenAnimationBuilder summary:

  1. ImplicitlyAnimatedWidgetState create AnimationController
  2. AnimatedWidgetBaseState listens for changes in the value of AnimationController and calls setState.
  3. _TweenAnimationBuilderState rewrite the build method, all parent calls setState, subclasses of the build will be invoked.
  4. Calculate the Tween value from the AnimationController value in the build and call back the Builder method passed in to the widget.

AnimatedBuilder

AnimatedBuilder, create and manage the AnimationController yourself, pass the AnimationController to the AnimatedBuilder, and pass in a callback Builder.

The code for AnimatedBuilder looks simpler

AnimatedBuilder summary:

  1. Manually create the AnimationController and pass it to AnimatedBuilder
  2. The AnimatedBuilder passes the AnimationController to the parent AnimatedWidget and overwrites the build method of the parent
  3. The value of the AnimationController is listened for in the State of the AnimatedWidget and setState is called
  4. Calling setState calls state’s build method, which calls the Widget’s build
  5. Since the AnimatedBuilder overrides the build method, the widget.build() called in _AnimatedState is equivalent to the build method of the called AnimatedBuilder
  6. The build of AnimatedBuilder is the builder callback that was passed in when the AnimatedBuilder was built.

conclusion

The source code for TweenAnimationBuilder and AnimatedBuilder doesn’t look too difficult, and it’s easy to see how the source code works once you understand how animation works. AnimationController listening, value calculation, ability matching between parent and child classes, etc.

At the end

In the whole animation chapter, we introduced implicit animation, explicit animation, AnimationController, Tween, Curve, combined animation, TickerProvider, source code analysis and other content.

The whole chapter allows us to quickly learn about Flutter animation, understand the principle of Flutter animation, and easily deal with various animation scenes.

reference

Official documentation for Flutter animation: api.flutter-io.cn/flutter/ani…

The Curve: API. Flutter. Dev/flutter/ANI…

How to choose the animation you want: medium.com/flutter/how…