Flutter- animation

Reference: https://flutter.io/docs/development/ui/animations
article will be synchronized to the micro-channel public number: Android Blog

First, the type of animation

Animation is divided into two categories: tween or physically based.

  • 1) Tween (Tween) Animation

"In between" for short. In tween, the definition of the start and end points, and the time line and the curve defines the transition time speed. How then calculated from the framework of transition from the starting point to the end point.

  • 2) physics-based animations

In the physics-based animation, motion is modeled as similar to the real-world behavior. For example, when you throw it in the ground where, depending on how fast drop speed, ball weigh, how far from the ground.

Similarly, the spring connected to the falling of the ball (and up) and connected to the ball down the rope is different.

Second, the animation Detailed

Flutter animation system based Animation objects, widget Animation objects can be read in the build function of the current value, and may monitor the animation state change.

1, the basic concept

Animation object is a core class Flutter animation library, it generates value guidance animation.

Animation animation object knows the current state (for example, it is a start, stop or move forward or backward), but it does not know what is displayed on the screen.
AnimationController management Animation.

The process CurvedAnimation abstracted as a non-linear curve.
Tween generated range value between the data object is used for performing animation. E.g., Tween may be generated between the color value from red to blue, or from 0 to 255.
Listeners use animation and StatusListeners monitor state changes.

2、Animation<double>

In the Flutter, Animation and UI rendering the object itself does not have any relationship. Animation is an abstract class, it has its current value and status (completed or stopped). One of the more common classes are Animation Animation <double>.

Animation object Flutter is sequentially generating a class value of a range between a period of time. Animation output object may be linear, curvilinear, or a step function can be designed in any other map.

Animation objects according to the control mode, the animation can be run in reverse, even in the middle of the switching direction.

Animation may also generate other types of values ​​other than double, as: Animation <Color> or Animation <Size>.

Animation stateful objects. You can get the current value of the animation by accessing its value property.

Animation UI rendering the object itself and has nothing to do.

3、CurvedAnimation

CurvedAnimation animation procedure is defined as a non-linear curve.

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

Curves class class defines many common curve, you can also create your own, for example:

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

4, AnimationController

AnimationController is a special Animation object in each frame refresh the screen, it will generate a new value. By default, AnimationController generated in a given period of time digital linearly from 0.0 to 1.0. For example, the following code creates an Animation object, but it does not start to run:

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

AnimationController derived from Animation <double>, so you can use wherever needed Animation object.

However, AnimationController have other methods to control the animation. For example, .forward () method can start the animation. Digital generation and screen refresh, and therefore usually produces 60 per figure, after generating each number, each object calls Listener object Animation added.

When you create a AnimationController, vsync you need to pass a parameter prevents offscreen animation (dollop: animation UI screen is not the current time) in the presence of vsync unnecessary consumption of resources.

SingleTickerProviderStateMixin by adding to the class definition, stateful object can be as the value of the vsync.

vsync objects binding animated visual timer to a widget, so when the widget is not displayed, the animation timer will pause when the widget is displayed again, the animation timer to resume execution, so you can avoid animation-related UI consumption of resources is not in the current screen. If you want to use the State custom objects as vsync, please include TickerProviderStateMixin.

5, Tween, tween

By default, the object range AnimationController from 0.0 to 1.0. If you need a different range, or different types of data, can be used to configure animations Tween different ranges to generate a value or data type. For example, the following example, Tween generated value from -200.0 to 0.0:
final Tween doubleTween = new Tween<double>(begin: -200.0, end: 0.0);

Tween is a stateless (Stateless) object needs to begin and end values. Tween sole responsibility is to define a mapping from the input to the output range of the range. Input range is usually 0.0 to 1.0, but this is not necessary.

Tween Inherited from Animatable <T>, not inherited from the Animation <T>. Animation Animatable and similar, not necessarily double output value. For example, ColorTween specify a transition between two colors.

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

  • 1) Tween object does not store any state. Instead, it provides evaluate (Animation <double> animation) The mapping function method is applied to the current value of the animation. Animation object can be the current value () method to get through the value. evaluate function also performs other processing, for example to ensure that each returns to the start and end states in the animation of 0.0 and 1.0.
  • 2) Tween.animate
    to use Tween object, call its Animate () method, passing in a controller object. For example, the following code generating integer values from 0 to 255 within 500 ms.
final AnimationController controller = new AnimationController(
    duration: const Duration(milliseconds: 500), vsync: this);
Animation<int> alpha = new IntTween(begin: 0, end: 255).animate(controller);

Note animate () returns an Animation, rather than a 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);

6, animations notice

Animation object can have a Listeners and StatusListeners listener, you can use addListener () and addStatusListener () to add. As long as the animation value changes, it will call the listener. One of the most common behavior is to call the Listener setState () to trigger UI reconstruction. Animation start, end, calls StatusListener moves forward or backward (as defined AnimationStatus).

Third, animation examples

Overview:
How addListener () and setState () to add a widget-based animation.
Each time a new digital animation generation, monitoring functions call setState ().
How to use the required parameters are defined AnimatedController vsync

1, rendering animation

No add animation code as follows:

import 'package:flutter/material.dart';

class LogoApp extends StatefulWidget {
  _LogoAppState createState() => new _LogoAppState();
}

class _LogoAppState extends State<LogoApp> {
  Widget build(BuildContext context) {
    return new Center(
      child: new Container(
        margin: new EdgeInsets.symmetric(vertical: 10.0),
        height: 300.0,
        width: 300.0,
        child: new FlutterLogo(),
      ),
    );
  }
}

void main() {
  runApp(new LogoApp());
}

Add AnimationController, passing a vsync object to achieve a progressively enlarged logo animation display, highlighted portions of the code modifications:

import 'package:flutter/animation.dart';
import 'package:flutter/material.dart';

class LogoApp extends StatefulWidget {
  _LogoAppState createState() => new _LogoAppState();
}

class _LogoAppState extends State<LogoApp> with SingleTickerProviderStateMixin {
  Animation<double> 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)
      ..addListener(() {//依赖animate返回的值调用addListener方法
        setState(() {
          // the state that has changed here is the animation object’s value
        });
      });
    controller.forward();
  }

  Widget build(BuildContext context) {
    return new Center(
      child: new Container(
        margin: new EdgeInsets.symmetric(vertical: 10.0),
        height: animation.value,
        width: animation.value,
        child: new FlutterLogo(),
      ),
    );
  }

  dispose() {
    controller.dispose();
    super.dispose();
  }
}

void main() {
  runApp(new LogoApp());
}

2, a simplified AnimatedWidget

Overview:
Use AnimatedWidget create a reusable animated widget. Isolated from the widget animated transitions, use AnimatedBuilder.

Flutter API提供的关于AnimatedWidget的示例包括:AnimatedBuilder、AnimatedModalBarrier、DecoratedBoxTransition、FadeTransition、PositionedTransition、RelativePositionedTransition、RotationTransition、ScaleTransition、SizeTransition、SlideTransition。

AnimatedWidget class allows you to () call in the animation code isolated widget code from a setState. AnimatedWidget not need to maintain a State object to hold the animation.

In the following example, the reconstruction, LogoApp now inherited from AnimatedWidget instead StatefulWidget. AnimatedWidget use animated when drawing the current value. LogoApp still manages AnimationController and Tween.

// Demonstrate a simple animation with AnimatedWidget

import 'package:flutter/animation.dart';
import 'package:flutter/material.dart';

class AnimatedLogo extends AnimatedWidget {
  AnimatedLogo({Key key, Animation<double> animation})
      : super(key: key, listenable: animation);

  Widget build(BuildContext context) {
    final Animation<double> animation = listenable;
    return new Center(
      child: new Container(
        margin: new EdgeInsets.symmetric(vertical: 10.0),
        height: animation.value,
        width: animation.value,
        child: new FlutterLogo(),
      ),
    );
  }
}

class LogoApp extends StatefulWidget {
  _LogoAppState createState() => new _LogoAppState();
}

class _LogoAppState extends State<LogoApp> with SingleTickerProviderStateMixin {
  AnimationController controller;
  Animation<double> animation;

  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();
  }

  Widget build(BuildContext context) {
    return new AnimatedLogo(animation: animation);
  }

  dispose() {
    controller.dispose();
    super.dispose();
  }
}

void main() {
  runApp(new LogoApp());
}

LogoApp Animation will be passed to the base class object and the container is provided with animation.value height and width, AnimatedWidget (base class) will automatically call addListener () and setState ().

3, monitoring the animation process

Overview:
notification to the animation using addStatusListener status changes, such as start, stop or reverse direction.
When the animation is completed, or return to its starting state, by reversing the direction infinite loop animate.

Know when to change the state of the animation is often useful, such as complete, forward or backward. You can get this notice by addStatusListener (). By modifying the above example code implements:

// Demonstrate a simple animation with AnimatedWidget

import 'package:flutter/animation.dart';
import 'package:flutter/material.dart';

class AnimatedLogo extends AnimatedWidget {
  AnimatedLogo({Key key, Animation<double> animation})
      : super(key: key, listenable: animation);

  Widget build(BuildContext context) {
    final Animation<double> animation = listenable;
    return new Center(
      child: new Container(
        margin: new EdgeInsets.symmetric(vertical: 10.0),
        height: animation.value,
        width: animation.value,
        child: new FlutterLogo(),
      ),
    );
  }
}

class LogoApp extends StatefulWidget {
  _LogoAppState createState() => new _LogoAppState();
}

class _LogoAppState extends State<LogoApp> with SingleTickerProviderStateMixin {
  AnimationController controller;
  Animation<double> animation;

  initState() {
    super.initState();
    controller = new AnimationController(
        duration: const Duration(milliseconds: 2000), vsync: this);
    animation = new Tween(begin: 0.0, end: 300.0).animate(controller);
    animation.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        controller.reverse();
      } else if (status == AnimationStatus.dismissed) {
        controller.forward();
      }
    });
    controller.forward();
  }

  Widget build(BuildContext context) {
    return new AnimatedLogo(animation: animation);
  }

  dispose() {
    controller.dispose();
    super.dispose();
  }
}

void main() {
  runApp(new LogoApp());
}

4, reconstituted with AnimatedBuilder

Overview:

  1. AnimatedBuilder

I do not know how to render the widget, do not know how to manage Animation object.
Use AnimatedBuilder animation build method described as part of another widget. If you just want to use animation definition of a reusable widget, please use AnimatedWidget.

Flutter API in AnimatedBuilder examples BottomSheetinclude: ExpansionTile, PopupMenu, ProgressIndicator, RefreshIndicator, Scaffold, SnackBar, TabBar, TextField, .

AnimatedBuilder tree is rendered in a separate class. And AnimatedWidget Similarly, AnimatedBuilder automatically listen for notifications from Animation objects and marked dirty (Dirty) the necessary control tree, there is no need to manually call addListener ().

  1. AnimatedBuilder may be separation of duties:
  • Display logo
  • Animation object definitions
  • Rendering transition effects

Rendering flowchart follows:


17572594-13a82f49ea6d70a0.png
image

Intermediate figures are created in three blocks of GrowTransition build () method. GrowTransition itself is stateless and has the final variables required to define the transition animation collection.

  • 1, build () function creates and returns AnimatedBuilder
  • 2, the (anonymous builder) method and objects as parameters LogoWidget
  • 3, rendering the work of conversion actually occurred in the (anonymous builder) method, which creates an appropriately sized Container to force scaling LogoWidget.
class GrowTransition extends StatelessWidget {
  GrowTransition({this.child, this.animation});

  final Widget child;
  final Animation<double> animation;

  Widget build(BuildContext context) {
    return new Center(
      child: new AnimatedBuilder(
          animation: animation,
          builder: (BuildContext context, Widget child) {
            return new Container(
                //child:要播放动画的widget对象
                height: animation.value, width: animation.value, child: child);
          },
          //child:要插入的widget对象
          child: child),
    );
  }
}

child looks like specified twice. However, what actually happens is that the child is transmitted to the external reference AnimatedBuilder, AnimatedBuilder passes it to the anonymous constructor, as the object and its child objects. The end result is rendered AnimatedBuilder inserted between two tree widget.

class LogoApp extends StatefulWidget {
  _LogoAppState createState() => new _LogoAppState();
}

class _LogoAppState extends State<LogoApp> with TickerProviderStateMixin {
  Animation animation;
  AnimationController controller;

  initState() {
    super.initState();
    controller = new AnimationController(
        duration: const Duration(milliseconds: 2000), vsync: this);
    final CurvedAnimation curve =
        new CurvedAnimation(parent: controller, curve: Curves.easeIn);
    animation = new Tween(begin: 0.0, end: 300.0).animate(curve);
    controller.forward();
  }

  Widget build(BuildContext context) {
    return new GrowTransition(child: new LogoWidget(), animation: animation);
  }

  dispose() {
    controller.dispose();
    super.dispose();
  }
}

void main() {
  runApp(new LogoApp());
}

InitState () method to create a AnimationController and a Tween, and then binding them by animate (). In the build () method to return the object with a LogoWidget GrowTransition as a child object, and a transition animation object for driving.

The complete code is as follows:

import 'package:flutter/animation.dart';
import 'package:flutter/material.dart';

class LogoWidget extends StatelessWidget {
  // Leave out the height and width so it fills the animating parent
  build(BuildContext context) {
    return new Container(
      margin: new EdgeInsets.symmetric(vertical: 10.0),
      child: new FlutterLogo(),
    );
  }
}

class GrowTransition extends StatelessWidget {
  GrowTransition({this.child, this.animation});

  final Widget child;
  final Animation<double> animation;

  Widget build(BuildContext context) {
    return new Center(
      child: new AnimatedBuilder(
          animation: animation,
          builder: (BuildContext context, Widget child) {
            return new Container(
                height: animation.value, width: animation.value, child: child);
          },
          child: child),
    );
  }
}

class LogoApp extends StatefulWidget {
  _LogoAppState createState() => new _LogoAppState();
}

class _LogoAppState extends State<LogoApp> with TickerProviderStateMixin {
  Animation animation;
  AnimationController controller;

  initState() {
    super.initState();
    controller = new AnimationController(
        duration: const Duration(milliseconds: 2000), vsync: this);
    final CurvedAnimation curve =
        new CurvedAnimation(parent: controller, curve: Curves.easeIn);
    animation = new Tween(begin: 0.0, end: 300.0).animate(curve);
    controller.forward();
  }

  Widget build(BuildContext context) {
    return new GrowTransition(child: new LogoWidget(), animation: animation);
  }

  dispose() {
    controller.dispose();
    super.dispose();
  }
}

void main() {
  runApp(new LogoApp());
}

5, parallel animation

Tween using a plurality of animation on the same controller, wherein each of the different effects Tween management animation. If required opacity and size variations in the production code Tween, and then may use FadeTransition SizeTransition.

One effect of each Tween management animation. E.g:

final AnimationController controller =
    new AnimationController(duration: const Duration(milliseconds: 2000), vsync: this);
final Animation<double> sizeAnimation =
    new Tween(begin: 0.0, end: 300.0).animate(controller);
final Animation<double> opacityAnimation =
    new Tween(begin: 0.1, end: 1.0).animate(controller);

It can be obtained by sizeAnimation.value size, opacity to get through opacityAnimation.value, but AnimatedWidget constructor accepts only an animated object. To solve this problem, this example creates its own Tween object and explicitly calculate these values.

Which method build .evaluate () function call on the parent Tween animated objects to calculate the desired size value and opacity.

The complete code is as follows:

import 'package:flutter/animation.dart';
import 'package:flutter/material.dart';

class AnimatedLogo extends AnimatedWidget {
  // The Tweens are static because they don't change.
  static final _opacityTween = new Tween<double>(begin: 0.1, end: 1.0);
  static final _sizeTween = new Tween<double>(begin: 0.0, end: 300.0);

  AnimatedLogo({Key key, Animation<double> animation})
      : super(key: key, listenable: animation);

  Widget build(BuildContext context) {
    final Animation<double> animation = listenable;
    return new Center(
      child: new Opacity(
        opacity: _opacityTween.evaluate(animation),
        child: new Container(
          margin: new EdgeInsets.symmetric(vertical: 10.0),
          height: _sizeTween.evaluate(animation),
          width: _sizeTween.evaluate(animation),
          child: new FlutterLogo(),
        ),
      ),
    );
  }
}

class LogoApp extends StatefulWidget {
  _LogoAppState createState() => new _LogoAppState();
}

class _LogoAppState extends State<LogoApp> with TickerProviderStateMixin {
  AnimationController controller;
  Animation<double> animation;

  initState() {
    super.initState();
    controller = new AnimationController(
        duration: const Duration(milliseconds: 2000), vsync: this);
    animation = new CurvedAnimation(parent: controller, curve: Curves.easeIn);

    animation.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        controller.reverse();
      } else if (status == AnimationStatus.dismissed) {
        controller.forward();
      }
    });

    controller.forward();
  }

  Widget build(BuildContext context) {
    return new AnimatedLogo(animation: animation);
  }

  dispose() {
    controller.dispose();
    super.dispose();
  }
}

void main() {
  runApp(new LogoApp());
}

6、AnimatedOpacity

This is a widget, there are several sub-attributes need to be defined:

  • opacity: 0.0 (not visible) to 1.0 (visible).
  • duration: How long executing the animation
  • child: widget execution animation

Complete example:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final appTitle = 'Opacity Demo';
    return MaterialApp(
      title: appTitle,
      home: MyHomePage(title: appTitle),
    );
  }
}

// The StatefulWidget's job is to take in some data and create a State class.
// In this case, our Widget takes in a title, and creates a _MyHomePageState.
class MyHomePage extends StatefulWidget {
  final String title;

  MyHomePage({Key key, this.title}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

// The State class is responsible for two things: holding some data we can
// update and building the UI using that data.
class _MyHomePageState extends State<MyHomePage> {
  // Whether the green box should be visible or invisible
  bool _visible = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: AnimatedOpacity(
          // If the Widget should be visible, animate to 1.0 (fully visible). If
          // the Widget should be hidden, animate to 0.0 (invisible).
          opacity: _visible ? 1.0 : 0.0,
          duration: Duration(milliseconds: 500),
          // The green box needs to be the child of the AnimatedOpacity
          child: Container(
            width: 200.0,
            height: 200.0,
            color: Colors.green,
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // Make sure we call setState! This will tell Flutter to rebuild the
          // UI with our changes!
          setState(() {
            _visible = !_visible;
          });
        },
        tooltip: 'Toggle Opacity',
        child: Icon(Icons.flip),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

Micro-channel public number:


17572594-2ba019badf85074a.jpg

Reproduced in: https: //www.jianshu.com/p/8656ce13cbfb

Guess you like

Origin blog.csdn.net/weixin_33749131/article/details/91342703