đŸ‘‰Animations Overview introduces the classes related to Flutter animation, and the interaction of these classes makes up the whole Flutter animation building.


The Animation system of Flutter is based on the Animation class. The Widget can read the current value of the animation or listen for changes in state, and then merge this information directly into its build method to make the Widget move. Widgets can also pass their animations to other widgets, which use the passed animations as a basis for more advanced animations.

Animation

The Animation class is important and is the backbone of the Animation framework implementation. An animation is a specific type of value that can be changed over the life of the animation. Simply put, an animation is a time versus value relationship. Most Animation widgets accept an object of type Animation as a parameter, from which the Widget reads the value of the current Animation and responds to changes in that value.

addListener

The animation notifies all listeners whenever the value of the animation changes. You can become a listener for the animation by calling the addListener method of the animation. In general, when the animation changes, the [State] object calls the [setState] method in the listening method body, and the Widget is rebuilt with the new animation value. The pseudocode is as follows:

Animation<T> animation;
@override
void initState() {
  super.initState();
  animation.addListener((){
    setState(() {
      
    });
  });
}
Copy the code

This pattern is very common. When the value of the animation changes, there are two widgets that help other widgets rebuild: the AnimatedWidget and the AnimatedBuilder. The AnimatedWidget’s usage scenario is to add animation effects to the StatelessWidget. All you need to do is inherit the AnimatedWidget and override the Build method. The use scenario for AnimatedBuilder is to animate a portion of a very long build. You need to pass in a Builder method when building the AnimatedBuilder.

addStatusListener

The animation also provides a status field, AnimationStatus, to indicate what the animation should do for the next time period, such as stop, continue, reverse, and so on. Whenever the animation’s state changes, the animation notifies all state listeners, and addStatusListener, which can be called to the animation, becomes its listener. A general animation is performed by an electioneering source. The state is the beginning of the time range or value range of the animation. For example, if the range of the animation is 0.0 to 1.0, then the state becomes dismissed when the animation value is 0.0. Animations are generally forward — forward (0.0 to 1.0), but can also be reverse — reverse (1.0 to 0.0). Finally, if the animation reaches the end of the range, the animation reaches the completed state.

AnimationController

Before creating an Animation, you need to create an AnimationController. The AnimationController has two functions. First, it inherits from the Animation and is itself an Animation. Second, it can control the animation, such as the animation forward, stop. In addition to basic animation usage, the AnimationController can also use physics simulators to create physical animations. Such as bouncing and so on.

Since AnimationController itself is a subclass of Animation, and animations can be nested, it is possible to build other animations on top of AnimationController. For example, you can build a ReverseAnimation for mirroring effects, or you can build a CurvedAnimation for a specific curve.

Tweens

Sometimes the animation is not a simple 0.0 to 1.0 range, so developers can use Tween

instead. Tween

can be computed based on the values of the procedure between begin and end, such as the color, the string, and so on. The computed result is the Tween value, or effect value. Tween values can be of a specified type. For example, ColorTween is the value of the color. RectTween is the value of the rectangle. Developers can also customize Tween values by inheriting from Tween and overriding the LERP method.

Tween

is only responsible for generating the true effect value based on the intermediate value generated by the animation process 0-1. In order to get the middle value of the current frame, the developer needs to figure out how to get that value, and addListener gets that middle value. There are two ways to combine Tween

with an animation to get a specific Tween value:

  1. Calculates the tween value directly from the current animation value. This approach is suitable for widgets (addListener) that are already listening for animations to be rebuilt in the listener.

  2. Animate tween values based on animation. The animate method returns a new tween animation rather than a single value. This method works for creating A new animation for another Widget (A) that reads and listens for the current tween value. A doesn’t care what the original value is, it just cares what the original corresponding tween value is. For example, if A only cares about red, it shows green, and it does the calculation based on red.

Animation, architecture

Animation is built on a few core building blocks.

Scheduler

SchedulerBinding is a singleton class that exposes the original Flutter scheduling process.

For animation, the key is frame scheduling. On the screen that should be displayed every frame, the Flutter’s engine will trigger the Begin Frame callback. The scheduler will send this callback to each callback listener. You can register as a listener by calling the scheduleFrameCallback() method. All registered listeners receive a timestamp of a frame in the form of Duration. Because the time stamps of the registrants are the same, the animations they trigger also appear to be synchronized, perhaps by a few milliseconds.

Tickers

The Ticker connects to the scheduler’s scheduleFrameCallback() and calls its own callback on each tick.

The Ticker can be started and stopped. A Future is generated at the beginning, and the Future is computed at the end.

For each tick, the Ticker invokes a callback, and the input parameter is the duration of the first tick.

Because the ticker passes the timestamp to the callback relative to the length of the first tick, all tickers are synchronized. If we open a third tick between two ticks, the time of their callback is the same. Like bus stops, all tickers are waiting for a periodic event (tick) to start moving (timing).

Simulations

Simulation is an abstract class that converts a time value to a double value and has the concept of completion.

In principle, simulations are stateless, but in practice some simulations, such as BouncingScrollSimulation and ClampingScrollSimulation, change their state irreversibly when they are queried.

Various Concrete Implementations gives some examples of different effects.

Animatables

Animatable is an abstract class that maps a double to a specific type. And Animatable is stateless and immutable.

Tweens

Tween

maps a double to a specific type, such as a color and so on. It is an Animatable. In the lerp method, it converts a double to a specific type.

Tween is stateless and immutable.

Composing animatables

Passing Animatable

A to the chain() method of Animatable

B will create A new Animatable C, and the effect of C is as follows: The original double is mapped to A, and then A to B.

Curves

Curve is an abstract class that converts a double value in the range 0.0 to 1.0 into a double value in the range 0.0 to 1.0. It’s also stateless and immutable. All it does is define the curve of the animation.

Animations

Animation is an abstract class that defines the protocol interface for the Animation: getting the value of the specified type of Animation, and the direction of the Animation. State of animation. Listener for animation value changes.

Some subclasses of animated value will not change, such as kAlwaysCompleteAnimation kAlwaysDismissedAnimation, AlwaysStoppedAnimation and so on. Listeners for these animations are not called either.

Some Animation subclasses are stateless and simply pass listeners to their parent Animation. Some of them are stateful.

Composable animations

Most animations accept an explicit parent Animation

. These animations are driven by the parent animation.

The input parameters of CurvedAnimation are: a parent Animation

, a forward Curve, and a reverse Curve, Curve. CurvedAnimation uses curves to calculate the input of the parent animation and uses the result as its own animation effect. CurvedAnimation is immutable and stateless.

Input parameter to ReverseAnimation: a parent Animation

that reverses the parent Animation. For example, the parent animation 0.2 has a value of 3 and 0.8 has a value of 6. So the value 0.2 for ReverseAnimation is 6, and the value 0.8 for ReverseAnimation is 3, just like a mirror. CurvedAnimation is immutable and stateless.

Input argument to ProxyAnimation: a parent Animation

that simply forwards the current value of the parent Animation. The parent animation is mutable.

TrainHoppingAnimation has two parent animations that switch between them when the animations cross.

Animation controllers

The AnimationController is a stateful Animation

that holds a Ticker inside and has a life cycle through the Ticker: start and stop. For each Ticker callback, which we will call tick, the AnimationController will perform the following process: Step 1: The tick parameter gets the time parameter. The second step is to pass the time parameters to the Simulation and get the effect values for the animation from the Simulation. During this process, if the Simulation report time is up and the animation reaches the animation duration, the AnimationController will stop itself.

AnimationController

The AnimationController requires upper and lower bounds for the animation and the duration of the animation.

In simple examples, such as forward() or reverse(). The AnimationController interpolates a series of values in the upper and lower ranges at a given time.

If you use repeat(), the AnimationController also inserts a series of values, but it doesn’t stop, it repeats.

If animateTo() is used, the AnimationController inserts a series of values between the current animation value and the given target value within a given time range. If no time range is given, and duration is null, then the AnimationController determines the animation speed using the default animation time and the animation’s default next and next cycles.

If you use Fling (), the simulator of the animation is created with Force, and the simulator is used to drive the AnimationController.

If animateWith() is used, the AnimationController is driven with the given simulator Simulation.

The methods described above all return a Future, which is provided by the Ticker. When the AnimationController stops or changes the emulator, the future returns the result.

conclusion