Skip to content

Latest commit

 

History

History
166 lines (100 loc) · 11.5 KB

File metadata and controls

166 lines (100 loc) · 11.5 KB

9.1 Introduction to Flutter Animation

In the UI framework of any system, the principle of animation implementation is the same, that is: changing the appearance of the UI multiple times quickly within a period of time; because the human eye will produce visual persistence, the final result is a "continuous "Animation, this is the same principle as the movie. We call a UI change an animation frame, which corresponds to a screen refresh, and an important indicator that determines the smoothness of an animation is the frame rate FPS (Frame Per Second), which is the number of animation frames per second. Obviously, the higher the frame rate, the smoother the animation will be! Generally speaking, for the human eye, if the frame rate of animation exceeds 16FPS, it will be relatively smooth. If it exceeds 32FPS, it will be very delicate and smooth. If it exceeds 32FPS, the human eye will basically not feel the difference. Since every frame of the animation needs to change the UI output, continuously changing the UI output within a period of time is more resource-intensive, and requires higher hardware and software systems of the device. Therefore, in the UI system, the average animation Frame rate is an important performance indicator, and in Flutter, 60FPS can be achieved under ideal circumstances, which is basically the same as the frame rate that native applications can achieve.

Animation abstraction in Flutter

In order to facilitate developers to create animations, different UI systems have abstracted animations. For example, in Android, an animation can be described by XML and then set to View. Animation is also abstracted in Flutter, mainly involving the four characters of Animation, Curve, Controller, and Tween. They work together to complete a complete animation. Let's introduce them one by one.

Animation

AnimationIt is an abstract class. It has nothing to do with UI rendering. Its main function is to save the interpolation and state of the animation; one of the more commonly used Animationclasses is . An object is a class that sequentially generates a value between Tweens over a period of time. The output value of the object throughout the execution of the animation can be linear, curve, a curve step function or any other function, etc., which the decision to. According to the control method of the object, the animation can run forward (from the start state to the end state), reverse run, and even switch directions in the middle. You can also generate other types of values ​​besides, such as: or . In each frame of the animation, we can get the current state value of the animation through the properties of the object .Animation<double>``Animation``Animation``Curve``Animation``Animation``double``Animation<Color>``Animation<Size>``Animation``value

Animation notification

We can Animationmonitor the changes of each frame of the animation and the execution state through the Animationfollowing two methods:

  1. addListener(); It can be used to Animationadd a frame listener, which will be called every frame. The most common behavior in the frame listener is to call after changing the state setState()to trigger the UI rebuild.
  2. addStatusListener(); It can Animationadd an "animation state change" listener; the AnimationStatusstate change listener will be called when the animation starts, ends, forward or reverse (see definition).

Readers only need to know the difference between frame listener and status listener. We will illustrate them with examples in later chapters.

Curve

The animation process can be uniform speed, uniform acceleration or first acceleration and then deceleration. In Flutter, the Curveanimation process is described by (curves). We call uniform animation linear (Curves.linear), while non-uniform animation is non-linear.

We can CurvedAnimationspecify the curve of the animation by, such as:

final CurvedAnimation curve =
   new CurvedAnimation(parent: controller, curve: Curves.easeIn);

CurvedAnimationAnd AnimationController(described below) are both types. A new animation object can be generated by packaging and it is in this way that we associate the animation with the curve executed by the animation. We specify the curve of the animation as , which means that the animation starts slower and ends faster. The Curves class is a preset enumeration class, which defines many commonly used curves. The following are several commonly used ones:Animation<double>``CurvedAnimation``AnimationController``Curve``Curves.easeIn

Curves

Animation process

linear

Uniform

decelerate

Uniform deceleration

ease

Start to accelerate, then slow down

easeIn

Slow at the beginning, fast behind

easeOut

Start fast, slow back

easeInOut

Start slow, then speed up, and finally slow down

In addition to those listed above , there are many other curves defined in the Curves class. I won’t introduce them one by one here. Readers can check the Curves class definition by themselves.

Of course, we can also create our own Curve, for example, we define a sine curve:

class ShakeCurve extends Curve {
 @override
 double transform(double t) {
   return math.sin(t * math.PI * 2);
 }
}

AnimationController

AnimationControllerFor controlling the animation, which contains animation start forward(), stop stop(), reverse playback reverse()method. AnimationControllerAt each frame of the animation, a new value will be generated. By default, AnimationControllera number from 0.0 to 1.0 (the default interval) is linearly generated within a given time period. For example, the following code creates an Animationobject (but does not start the animation):

final AnimationController controller = new AnimationController(
   duration: const Duration(milliseconds: 2000), vsync: this);

AnimationControllerThe interval for generating numbers can be specified by lowerBoundsum upperBound, such as:

final AnimationController controller = new AnimationController( 
duration: const Duration(milliseconds: 2000), 
lowerBound: 10.0,
upperBound: 20.0,
vsync: this
);

AnimationControllerDerived from , so it can be used wherever an object is needed . However, there are other methods of controlling the animation, for example, the method can start the forward animation and the reverse animation can be started. The animation frame is generated after the animation starts. Each time the screen is refreshed, it is an animation frame. In each frame of the animation, the current animation value ( ) will be generated according to the animation curve , and then constructed according to the current animation value UI, when all animation frames are triggered in turn, the animation values ​​will change in turn, so the constructed UI will also change in turn, so we can finally see a completed animation. In addition, at each frame of the animation, the object will call its frame listener, and when the animation state changes (such as the end of the animation), it will call the state change listener.Animation<double>``Animation``AnimationController``forward()``reverse()``Animation.value``Animation

durationRepresents the duration of the animation, through which we can control the speed of the animation.

Note : In some cases, the animation value may exceed the range AnimationControllerof [0.0, 1.0], depending on the specific curve. For example, the fling()function can simulate a finger throwing animation based on the speed and force of our finger sliding (throwing), so its animation value can be outside the range of [0.0, 1.0]. That is, according to the selected curve, CurvedAnimationthe output can have a larger range than the input. For example, elastic curves such as Curves.elasticIn will generate values ​​larger or smaller than the default range.

Ticker

When creating one AnimationController, you need to pass a vsyncparameter, it receives a TickerProvidertype of object, and its main responsibility is to create Ticker, defined as follows:

abstract class TickerProvider {
 //通过一个回调创建一个Ticker
 Ticker createTicker(TickerCallback onTick);
}

Flutter application at startup will bind a SchedulerBindingthrough SchedulerBindingcan be added to each screen refresh callback, and Tickeris through SchedulerBindingto add a callback to refresh the screen, so that each screen refresh will be called TickerCallback. Use Ticker(instead Timer) to drive the animation will prevent (UI when the animation is not the current screen, such as when the lock screen) off-screen animation consume resources unnecessarily, because the binding will be notified when Flutter in screen refresh SchedulerBinding, and Tickeris subject to SchedulerBindingdriving Yes, because the screen will stop refreshing after the screen is locked, it Tickerwill not trigger again.

Usually we will SingleTickerProviderStateMixinadd to Statethe definition, and then use the State object as vsyncthe value, which can be seen in the following example.

Tween

By default, AnimationControllerthe range of object values ​​is [0.0, 1.0]. If we need to build UI animation values ​​in different ranges or different data types, we can use Tweento add mapping to generate values ​​of different ranges or data types. For example, like the following example, Tweenthe value of [-200.0, 0.0] is generated:

final Tween doubleTween = new Tween<double>(begin: -200.0, end: 0.0);

TweenThe constructor needs beginand endtwo parameters. TweenThe only responsibility is to define the mapping from the input range to the output range. The input range is usually [0.0, 1.0], but this is not necessary, we can customize the required range.

TweenInherited from , not inherited from , mainly defines the mapping rules of animation values.Animatable<T>``Animation<T>``Animatable

Let's look at an example of ColorTween mapping the animation input range to the transition output between two color values:

final Tween colorTween =
   new ColorTween(begin: Colors.transparent, end: Colors.black54);

TweenThe object does not store any state, on the contrary, it provides a method, it can get the current mapping value of the animation. The current value of the object can be retrieved by methods. The function also performs some other processing, such as ensuring that the start and end states are returned when the animation value is 0.0 and 1.0, respectively.evaluate(Animation<double> animation)``Animation``value()``evaluate

Tween.animate

To use the Tween object, you need to call its animate()method and then pass in a controller object. For example, the following code generates an integer value from 0 to 255 in 500 milliseconds.

final AnimationController controller = new AnimationController(
   duration: const Duration(milliseconds: 500), vsync: this);
Animation<int> alpha = new IntTween(begin: 0, end: 255).animate(controller);

Note that one is animate()returned Animation, not one Animatable.

The following example builds a controller, a curve, and a Tween:

final AnimationController controller = new AnimationController(
   duration: const Duration(milliseconds: 500), vsync: this);
final Animation curve =
   new CurvedAnimation(parent: controller, curve: Curves.easeOut);
Animation<int> alpha = new IntTween(begin: 0, end: 255).animate(curve);