preface

Read many articles about writing Flutter animation, but most of them are copied from documents, and some of them are you retweet mine, I retweet yours. Many articles do not add their own understanding of knowledge, do not know why to do this. To this end, I plan to write a Flutter animation of my own understanding.


Summary of the animation

There are two types of animation in Flutter: Tween based or physics-based.

Tween animation

Short for “in between”. In tween animation, start and end points, time lines, and curves that define transformation time and speed are defined. The framework then calculates how to transition from the start point to the end point.

Physics-based animation

In physics-based animation, motion is simulated to resemble real-world behavior. For example, when you throw a ball, where it lands depends on how fast it is thrown, how heavy it is, and how far it is from the ground. Similarly, a ball attached to a spring is dropped (and bounced) in a different way than a ball attached to a string.


Basic concept

1, Animation object

  • It is a core class in the Flutter animation library that generates values that guide the animation. This value includes color, size, and so on.
  • It knows the current state of the animation (start, stop, reverse, finish), but it doesn’t know what the UI rendered on the screen is, which means it doesn’t care about the UI rendering of your animation object.
  • It is an abstract class, and the implementation of concrete functions is done by its subclasses.
  • A commonly used Animation class is Animation

    , which generates values in the range (0.0-1.0) by default.


2,CurvedAnimation

It is a subclass of Animation<double>, which defines the Animation process as a non-linear curve, that is, what is the path of our Animation, or what form is used to represent our Animation.


3,AnimationController

It is a subclass of Animation

. It is a special Animation object that generates a new value every frame that the screen refreshes. By default, the AnimationController generates linear numbers from 0.0 to 1.0 over a given period of time. From the name of the class, you can know what it means: animation controller, which can control the state of the animation, monitor the execution state of the animation, listen to the value generated during the animation.

When creating an AnimationController, you pass a vsync parameter that prevents the animation’s UI from consuming unnecessary resources when it is not on the current screen. By putting a SingleTickerProviderStateMixin added to the class definition, can be stateful object as the value of vsync. For example: when our phone receives an incoming call, the interface jumps to the connected screen, and the animation that was running before the call is paused.


4,Tween

By default, the AnimationController object generates values in the range (0.0,1.0). If you need different ranges or different data types, you can use Tween to configure the animation to generate values for different ranges or data types.


Summary of concepts:

  • Animation is the core abstract class of Animation, and its commonly used class object is Animation

    .
  • Both CurvedAnimation and AnimationController are derived from Animation

    . The former manages Animation presentation, while the latter manages Animation interpolation, state, and so on.
  • If the default values do not meet our needs, we use Tween to customize the interpolation range


case

Zoom in the animation

Dart puts a component that performs the animation inside the body. The main code is in that component

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(

        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Flutter animation"), ), body:Animation1() , ); }}Copy the code

Animation1.dart component file

import 'package:flutter/material.dart';

///create by:Administrator
///create at:2019-09-28 14:43
///des:

class Animation1 extends StatefulWidget {
  @override
  _Animation1State createState() => _Animation1State();
}

class _Animation1State extends State<Animation1>
    with SingleTickerProviderStateMixin {
  Animation animation;
  AnimationController animationController;
  
  @override
  void initState() { super.initState(); animationController = AnimationController(vsync: this, duration: Duration(milliseconds: 2000)); Animation = Tween(begin: 10.0, end: 200.0). Animate (animationController); Anim.addlistener ((){// Set the interpolation listener, throughsetState() rerenders the UIsetState(() { }); }); animationController.forward(); } @override Widget build(BuildContext context) {return Center(
      child:Container(
        width: animation.value,
        height: animation.value,
        color: Colors.redAccent,
      ),
    );
  }

  @override
  void dispose() { super.dispose(); animationController.dispose(); // Release resources}}Copy the code

3, the details:

  • The entire effect of the animation is to enlarge the Container from 10.0 to 200.0. The animation lasts for 2 seconds.
  • Tween creates custom interpolations in the range (10.0,200.0) where the Container changes values during animation execution. We then pass in the animate() method to the animationController and get the Animation object. As mentioned earlier, this object has control over the Animation and we need to know the state and interpolation of the Animation
  • Call setState() to re-render the UI by setting the interpolation listener.
  • Start the animation with the animationController.


AnimatedWidget simplifies magnified animations

  • The AnimatedWidget class allows you to access thesetState()The widget code is separated from the animation code in the call. The AnimatedWidget does not need to maintain a State object to hold the animation.

  • AnimatedWidget is an abstract class inherited from StateFulWidget.

Animation2.dart component file

import 'package:flutter/material.dart';

///create by:Administrator
///create at:2019-09-28 14:43
///des:

class Animation2 extends StatefulWidget {
  @override
  _Animation2tate createState() => _Animation2tate();
}

class _Animation2tate extends State<Animation2>
    with SingleTickerProviderStateMixin {
  Animation animation;
  AnimationController animationController;

  @override
  void initState() { super.initState(); animationController = AnimationController(vsync: this, duration: Duration(milliseconds: 2000)); Animation = Tween(begin: 10.0, end: 200.0). Animate (animationController); / / custom interpolation range animationController. Forward (); } @override Widget build(BuildContext context) {return Center(
      child:CustomWidget(animation: animation),
    );
  }

  @override
  void dispose() { super.dispose(); animationController.dispose(); Class CustomWidget extends AnimatedWidget{CustomWidget({Key Key, Animation<double> animation}) : super(key: key, listenable: animation); @override Widget build(BuildContext context) { final Animation<double> animation = listenable;returnContainer( width: animation.value, height: animation.value, color: Colors.redAccent, ); }}Copy the code

2, the description:

We replaced the Child in the animation component with a CustomWidget, removing animation listening and state refreshing. The replacement component is inherited from the AnimatedWidget and receives an Animation object. The addListener() and setState() methods are automatically called in the AnimatedWidget(base class) to complete the UI refresh, and the animation executes as before.

To simplify operations, we need to monitor the animation execution management state ourselves. In this case, we need to define the animation rules and hand them to the AnimatedWidget, leaving it to manage the animation state and refresh the UI.

In addition, we write in this way, to achieve the effect of animation reuse, from this level can also be understood as a simplification of the animation.

I feel that this simplification is a little farfetched on the whole. I can only understand it like this for the time being. Readers can leave comments below for better understanding, thank you


AnimatedBuilder Reconstructs the animation

In both of the previous animation implementations, our interpolation intruded into the component, as shown in the following code.

 return Container(
      width: animation.value,
      height: animation.value,
      color: Colors.redAccent,
    );Copy the code

What if we want to change this component, for example, we want to change the animation object (the component that needs to perform the animation) to a picture, or something else, then we have to modify the animation object, is not very troublesome, and the reuse level is very low. So is there any way we can separate the animation objects, the animation rules, and do their jobs. This is where the AnimatedBuilder comes in. It reconstructs the UI from animation interpolation using anonymous constructors, automatically managing animation state and refreshing.

In addition, this refresh is partial and applies only to animated objects rather than the entire page, so I think this refresh is more resource-efficient than the above two.


Animation3.dart component file

import 'package:flutter/material.dart';

///create by:Administrator
///create at:2019-09-28 17:29
///des:

class Animation3 extends StatefulWidget {
  @override
  _Animation3State createState() => _Animation3State();
}

class _Animation3State extends State<Animation3> with SingleTickerProviderStateMixin{
  Animation animation;
  AnimationController controller;

  initState() { super.initState(); controller = new AnimationController(duration: const Duration(milliseconds: 2000), vsync: this); Animation = new Tween(begin: 0.0, end: 300.0). Animate (controller); Controller.forward (); } @override Widget build(BuildContext context) {return  GrowBuild(child: MyContainer(), animation: animation);
  }

  dispose() { controller.dispose(); super.dispose(); } class GrowBuild extends StatelessWidget {GrowBuild({this.child, this.animation}); final Widget child; final Animation<double> animation; Widget build(BuildContext context) {returnnew Center( child: new AnimatedBuilder( animation: animation, builder: (BuildContext context, Widget Child) {// The anonymous constructor rebuilds the child based on the animation interpolation and then rerendersreturnnew Container( height: animation.value, width: animation.value, child: child); }, child: child), // rerender the child echo); Class MyContainer extends StatelessWidget{@override Widget build(BuildContext context) {returnContainer(width: 100.0, height: 200.0, color: Colors. RedAccent,); }}Copy the code


Conclusion:

The above is my personal opinion on the basics of Flutter animation. Not all of them are correct. Please correct any mistakes.

In addition, readers can leave comments and discuss with each other in some places. Thank you.