All the code has been uploaded togithubIf you find it useful, please give a STAR. Thank you.

introduce

  • Introduction to Common Classes

    • Tween

      Tween animation, you can define the start and end points, the animation will be executed according to the start and end points given the range, each frame takes a value, can be used to draw a new view, a frame drawing stroke animation effect.

      Tween<T>(begin: begin, end: end)
      Copy the code

      The begin and end types are determined by the type passed in by Tween.

    • Animation

      This is a value used to manage the animation state and generate each frame of the animation. In this class, you can set the animation per-frame listener and animation state listener.

    • CurvedAnimation, which inherits the Animation, can be used to implement animations with curve models. Click Curves to see more

    • AnimationController

      Animation controller, is used to manage the Animation, use AnimationController need incoming vsync, usually through the use of AnimationController SingleTickerProviderStateMixin were mixed with the class, Just pass in the current this, or TickerProviderStateMixin when a class has more than one AnimationController. You also need to pass in a duration to control the animation execution time.

    • AnimatedWidget, an animation widget that isolates an animated view from the main view without causing the main view to redraw when the animation is drawn. This is an abstract class that is usually implemented through a derived class of the AnimatedWidget.

    • AnimatedBuilder inherits from the AnimatedWidget and is easier to use.

  • Animation adds listeners

    Adding listeners to an Animation is an operation on the Animation.

    • addListener

      You can listen on every frame

      Animation.addlistener (() {// Prints the value of each frameprint(animation.value);
      });
      Copy the code
    • addStatusListener

      Used to listen to the state of the Animation

      animation.addStatusListener((AnimationStatus status) {
          if(status = = AnimationStatus.com pleted) {/ / animation complete}else if(status = = AnimationStatus. Dismissed) cancel} {/ / animationelse if(status == animationStatus.reverse) {// Animation reverse}else if(status == animationStatus.forward) {// Animation forward (start)}});Copy the code
  • Animation State Introduction

    • Dismissed animation
    • Forward animates forward, usually calling the next method to start the animation.
    • Reverse Animation
    • Completed The animation
  • AnimationControl The animation control is the AnimationController to perform the animation.

    • Forward animation forward, can be used to start the animation.
    • Reverse Animation reverse, which can be used to start animation.
    • Reset Reset animation
    • Stop Stop animation
    • Repeat repeats the animation, which can be used to start the animation.
  • Practice mode of animation

    • Tween is used alone by setting an addListener to the Animation to capture each frame’s callback to redraw the view
    import 'package:flutter/material.dart'; Class DisplacementPage extends StatefulWidget {@override DisplacementPageState createState() => DisplacementPageState(); } class DisplacementPageState extends State<DisplacementPage> with SingleTickerProviderStateMixin { AnimationController controller; Animation<Offset> animation; @override voidinitState() { super.initState(); controller = AnimationController(vsync: this, duration: Duration(milliseconds: 1000)); Offset begin = Offset(0.0, 0.0); Offset end = Offset(0.0, 200); animation = Tween<Offset>(begin: begin, end: end).animate(controller) .. addListener(() {setState(() {});
          })
          ..addStatusListener((AnimationStatus status) {
            if (status == AnimationStatus.completed) {
              controller.reverse();
            } else if(status == AnimationStatus.dismissed) { controller.forward(); }}); controller.forward(); } @override Widget build(BuildContext context) {return Scaffold(
          appBar: AppBar(
            title: Text('displacement'),
            centerTitle: true,
          ),
          body: Align(
            child: Container(
              width: 100,
              height: 100,
              margin: EdgeInsets.only(top: animation.value.dy),
              color: Colors.green,
            ),
          ),
        );
      }
    
      @override
      void dispose() { controller.dispose(); super.dispose(); }}Copy the code
    • AnimatedBuilder use

      AnimateBuilder inherits the AnimatedWidget, passing in an AnimationController and Builder. Builder is a TransitionBuilder virtual type, whose real type is a Widget

       typedef TransitionBuilder = Widget Function(BuildContext context, Widget child);
      Copy the code

      Show with AnimatedBuilder animation effects, the system also provides us with the Transform, Transform is inherited SingleChildRenderObjectWidget, used by the Transform construct the following three ways:

      • Transform.rotate

        The rotation transform requires passing in a Widget with oneangle, Angle is the value of the Angle, 0° is 0, 360° is 2π π is usually used math.pi, which is required when using thisimport 'dart:math' as math;
      • The move Transform requires passing in a Widget and offset
      • Transform.scaleThe zoom transform needs to be passed in with a WidgetscaleThe values of the scale isRelative to their ownMultiples of size, e.gScale: 1.2Zoom in to 1.2 times its own size
        import 'package:flutter/material.dart';
        import 'package:flutter_animation/util.dart';
        import 'dart:math' as math;
        
        ///AnimatedBuilder
        class AnimatedBuilderPage extends StatefulWidget {
        @override
        AnimatedBuilderPageState createState() => AnimatedBuilderPageState();
        }
        
        class AnimatedBuilderPageState extends State<AnimatedBuilderPage> with SingleTickerProviderStateMixin {
        AnimationController controller;
        
        //旋转
        Animation<double> rotate;
        
        //移动
        Animation<Offset> translate;
        
        //缩放
        Animation<double> scale;
        
        @override
        void initState() {
          super.initState();
        
          controller = AnimationController(vsync: this, duration: Duration(milliseconds: 2000));
        
          CurvedAnimation curvedAnimation = CurvedAnimation(parent: controller, curve: Curves.linear);
        
          rotate = Tween<double>(begin: 0, end: math.pi * 2).animate(curvedAnimation);
          translate = Tween<Offset>(begin: Offset(0, 0), end: Offset(300, 50)).animate(curvedAnimation);
          scale = Tween<double>(begin: 1, end: 2).animate(curvedAnimation);
        
          controller.repeat();
        }
        
        @override
        Widget build(BuildContext context) {
          return Scaffold(
            appBar: AppBar(
              title: Text('AnimatedBuilder'),
              centerTitle: true,
            ),
            body: Align(
              child: Column(
                children: <Widget>[
                  titleBarWidget(
                      title: 'AnimatedBuilder separates the animation view from the home page. SetState called during animation execution will only redraw the view in AnimatedBuilder, not the home page. '
                  '\nAnimatedBuilder builder needs to return a TransitionBuilder,'
                  '\n There can be three kinds of animation when building TransitionBuilder, '
                  '\ nTransform. Rotate rotating'
                  'move \ nTransform. Translate'
                  '\ nTransform scale scale'),
                  sizedBox,
                  AnimatedBuilder(
                    animation: controller,
                    builder: (context, child) {
                      return Transform.rotate(
                        angle: rotate.value,
                        child: Container(
                          width: 100,
                          height: 100,
                          color: Colors.green,
                          child: Icon(Icons.android, color: Colors.white),
                        ),
                      );
                    },
                  ),
                  sizedBox,
                  AnimatedBuilder(
                    animation: controller,
                    builder: (context, child) {
                      return Transform.translate(
                        offset: translate.value,
                        child: Container(
                          width: 100,
                          height: 100,
                          color: Colors.green,
                          child: Icon(Icons.android, color: Colors.white),
                        ),
                      );
                    },
                  ),
                  sizedBox,
                  AnimatedBuilder(
                    animation: controller,
                    builder: (context, child) {
                      returnTransform.scale( scale: scale.value, child: Container( width: 100, height: 100, color: Colors.green, child: Icon(Icons.android, color: Colors.white), ), ); },),],),),); } @override voiddispose() { controller.dispose(); super.dispose(); }}Copy the code

      Note: The Transform changes during the application drawing phase. The widgets in the Transform are sized and positioned during the layout phase, and the Transform animation changes without affecting other views.

    • Transition Transition is a generic term for implementing an animation that inherits the AnimatedWidget. It can be used in the following ways:

      • SlideTransition
      • ScaleTransition scaling
      • RotationTransition
      • The SizeTransition
      • FadeTransition
      • PositionedTransition Locates the transition
      • The transition to RelativePositionedTransition relative positioning
      • DecoratedBoxTransition Decorates the transition
      • AlignTransition aligntransitions
      • DefaultTextStyleTransition default font style transition

      import 'package:flutter/material.dart';
      import 'package:flutter_animation/util.dart';
      
      ///Transition
      class TransitionPage extends StatefulWidget {
        @override
        TransitionPageState createState() => new TransitionPageState();
      }
      
      class TransitionPageState extends State<TransitionPage> with SingleTickerProviderStateMixin {
        AnimationController controller;
      
        //旋转
        Animation<double> rotate;
      
        //移动
        Animation<Offset> translate;
      
        //缩放
        Animation<double> scale;
      
        @override
        void initState() { super.initState(); controller = AnimationController(vsync: this, duration: Duration(milliseconds: 2000)); CurvedAnimation = CurvedAnimation(parent: controller, curve: Curves. Linear); rotate = Tween<double>(begin: 0, end: 1).animate(curvedAnimation); Translate = Tween<Offset>(begin: Offset(0, 0), end: Offset(1.5, 1.5)). Animate (curvedAnimation); scale = Tween<double>(begin: 1, end: 2).animate(curvedAnimation); controller.repeat(); } @override Widget build(BuildContext context) {return Scaffold(
            appBar: AppBar(
              title: Text('Transition'),
              centerTitle: true,
            ),
            body: Align(
              child: Column(
                children: <Widget>[
                  titleBarWidget(title: 'the Transition inherit AnimatedWidget'),
                  sizedBox,
                  RotationTransition(
                    turns: rotate,
                    child: Container(
                      width: 100,
                      height: 100,
                      color: Colors.green,
                      child: Icon(Icons.android, color: Colors.white),
                      ),
                  ),
                  sizedBox,
                  SlideTransition(
                    position: translate,
                    child: Container(
                      width: 100,
                      height: 100,
                      color: Colors.green,
                        child: Icon(Icons.android, color: Colors.white),
                    ),
                  ),
                  sizedBox,
                  ScaleTransition(
                    scale: scale,
                    child: Container(
                      width: 100,
                      height: 100,
                      color: Colors.green,
                      child: Icon(Icons.android, color: Colors.white),
                    ),
                  ),
                ],
              ),
            ),
          );
        }
      
        @override
        void dispose() { controller.dispose(); super.dispose(); }}Copy the code

      Note that these constructors pass in values that are relative to their size, Angle, position, and coordinate multiples. See the build method for details

Animation types

  • Filling between animation

    • introduce

      When creating a Tween, you can also use the following types to create a Tween. These types are inherited from Tween, but with an additional lERP processing on top of Tween

    • type

      • ReverseTween reverse
      • ColorTween color
      • SizeTween size
      • RectTween rectangle
      • IntTween integer
      • StepTween gradient
      • ConstantTween constant
      • CurveTween curve
  • Physics-based animation

    • introduce

      Physics-based animation simulates everyday imaginings, such as a ball landing, a rubber band pulling up and releasing, and so on.

    • type

      There are too many types, check out the Curves for details

    • use

      AnimationController controller; // scale Animation<double> scale; @override voidinitState() { super.initState(); controller = AnimationController(vsync: this, duration: Duration(milliseconds: 2000)); CurvedAnimation = CurvedAnimation(parent: controller, curve: Curves. Linear); scale = Tween<double>(begin: 1, end: 2).animate(curvedAnimation); controller.repeat(); }Copy the code

Common animation

  • The animation list

    AnimatedList Animates an item in the ListView. We can pass in a Tween animation as needed, using the following code:

Class AnimatedListPage extends StatefulWidget {@override AnimatedListPageState createState() => AnimatedListPageState(); } class AnimatedListPageState extends State<AnimatedListPage> { final GlobalKey<AnimatedListState> globalKey = GlobalKey<AnimatedListState>(); int index = 5; inttype= 1; ItemWidget ({context, animation, index}) {Widget child = Container(width: double. Infinity, height: 100, margin: EdgeInsets.only(left: 16, top: 16, right: 16), color: Colors.primaries[index], ); Widget size = SizeTransition(sizeFactor: animation, child: child); Widget scale = ScaleTransition(scale: animation, child: child); Widget fade = FadeTransition(opacity: animation, child: child); switch (type) {
        case 1:
          return size;
        case 2:
          return scale;
        case 3:
          return fade;
        default:
          returnsize; BuildItemWidget (context, index, animation) {returnitemWidget(context: context, index: index, animation: animation); RemoveItemBuilder (BuildContext Context, Animation<double> Animation) {return itemWidget(context: context, index: index, animation: animation);
    }


    @override
    Widget build(BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          title: Text('AnimatedList'),
          actions: <Widget>[
            IconButton(
              icon: Icon(Icons.add_circle),
              onPressed: () {
                index += 1;
                globalKey.currentState.insertItem(index - 1);
              },
            ),
            IconButton(
              icon: Icon(Icons.remove_circle),
              onPressed: () {
                if (index > 1) {
                  index -= 1;
                  globalKey.currentState.removeItem(index, removeItemBuilder);
                }
              },
            ),
            PopupMenuButton(
              icon: Icon(Icons.more_vert),
              itemBuilder: (context) {
                return [
                  PopupMenuItem(
                    child: Text('Unfolded and folded'),
                    value: 1,
                  ),
                  PopupMenuItem(
                    child: Text('Zoom out'),
                    value: 2,
                  ),
                  PopupMenuItem(
                    child: Text('gradient'),
                    value: 3,
                  ),  
                ];
              },
              onSelected: (value) {
                type = value;
                setState(() {}); }, ), ], ), body: AnimatedList( key: globalKey, itemBuilder: buildItemWidget, initialItemCount: index, ), ); }}Copy the code
  • Shared elements

    Hero = Hero = Hero = Hero = Hero = Hero = Hero = Hero = Hero = Hero = Hero = Hero

import 'package:flutter/material.dart';
import 'package:flutter_animation/util.dart'; Class PhotoWidget extends StatelessWidget {final double width; final double height; final String path; PhotoWidget({this.width = double.infinity, this.height, this.path}); @override Widget build(BuildContext context) {return SizedBox(
      width: width,
      child: Hero(
        tag: path,
        child: Image.asset(
          path,
          fit: BoxFit.contain,
          package: 'flutter_animation',),),); Class HeroAnimationPage extends StatefulWidget {@Override HeroAnimationPageState createState() => new HeroAnimationPageState(); } class HeroAnimationPageState extends State<HeroAnimationPage> { @override Widget build(BuildContext context) {return new Scaffold(
      appBar: new AppBar(
        title: new Text('Shared Elements'),
        centerTitle: true,
      ),
      body: Align(
        child: SingleChildScrollView(
          child: Column(
            children: <Widget>[
              titleBarWidget(title: 'Flutter animation is divided into Tween and physics animation '),
              sizedBox,
              PhotoWidget(
                width: 300,
                height: 100,
                path: 'assets/images/photo.png',
              ),
              sizedBox,
              buttonWidget(
                title: 'View details', onPressed: () { toPage(context, PhotoDetail()); }, [, [, (), (), (), (); } void toPage(BuildContext context, Widget widget) { Navigator.push(context, MaterialPageRoute(builder: (context) => widget)); Class PhotoDetail extends StatelessWidget {@override Widget build(BuildContext context) {return new Scaffold(
      appBar: new AppBar(
        title: new Text('Shared Elements - Details'),
        centerTitle: true,
      ),
      body: Column(
        children: <Widget>[
          PhotoWidget(
            width: double.infinity,
            height: 300,
            path: 'assets/images/photo.png',
          ),
          Padding(
            padding: EdgeInsets.all(16),
            child: Text('\t\t\ T mengchi ·D· Luffy, the leading role of the Japanese cartoon "The King of The Sea", nicknamed "straw Hat" Luffy, straw hat pirates, captain of the ship, one of the most evil generation. '
                'One and a half billion berri is offered for the ability of rubber fruit. The dream is to find the legendary One Piece and become the King of One Piece. '
                'n n t t t luffy is a positive and optimistic person with a clear love and hate. He attaches great importance to his partner and is unwilling to be subordinate to others. He is super interested in anything dangerous. '
                'Unlike other traditional sea thieves, he does not kill for wealth, but enjoys the adventure and freedom of being a sea thief. '() [() [() [() }}Copy the code
  • Staggered animation

    Interleaved animation is a combination of multiple animations, and the Interval is used to control the animation execution time. The code is as follows:

import 'package:flutter/material.dart'; / / / staggered animation class StaggeredAnimationPage extends StatefulWidget {@ override StaggeredAnimationPageState createState () = > StaggeredAnimationPageState(); } class StaggeredAnimationPageState extends State<StaggeredAnimationPage> with SingleTickerProviderStateMixin { AnimationController controller; Animation<Offset> translate; Animation<double> sizeWidth; Animation<double> sizeHeight; Animation<double> radius; Animation<Color> color; Animation<double> opacity; @override voidinitState() { super.initState(); controller = AnimationController(vsync: this, duration: Duration(seconds: 2)); translate = Tween<Offset>(begin: Offset(0, 0), end: Offset(0, 200)).animate( CurvedAnimation( parent: Controller, curve: Interval(0, 0.3, Curve: Curves. Linear),); sizeWidth = Tween<double>(begin: 50, end: 200).animate(CurvedAnimation( parent: controller, curve: Interval(0.3, 0.4, Curve: Curves. Linear),); sizeHeight = Tween<double>(begin: 50, end: 200).animate(CurvedAnimation( parent: controller, curve: Interval(0.4, 0.6, Curve: Curves. Linear),); radius = Tween<double>(begin: 0, end: 100).animate(CurvedAnimation( parent: controller, curve: Interval(0.6, 0.7, Curve: Curves. Linear),); color = ColorTween(begin: Colors.green, end: Colors.red) .animate(CurvedAnimation( parent: controller, curve: Interval(0.6, 0.8, curve: recovery.bounceout),); Opacity = Tween<double>(begin: 0, end: 1). Animate (CurvedAnimation(parent: controller, curve: Interval(0.8, 1.0, curve: Interval) Curves.linear), )); controller.addStatusListener((AnimationStatus status) {if (status == AnimationStatus.completed) {
        controller.reverse();
      } else if(status == AnimationStatus.dismissed) { controller.forward(); }}); controller.forward(); } @override Widget build(BuildContext context) {return Scaffold(
      appBar: AppBar(
        title: Text('Staggered animation'),
      ),
      body: Align(
        alignment: Alignment.topCenter,
        child: AnimatedBuilder(
          animation: controller,
          builder: (context, child) {
            returnTransform.translate( offset: translate.value, child: Container( width: sizeWidth.value, height: sizeHeight.value, decoration: BoxDecoration( border: Border.all(color: Colors.black, width: 1), borderRadius: BorderRadius.all(Radius.circular(radius.value)), color: color.value, ), child: Opacity( opacity: opacity.value, child: Icon( Icons.android, size: 50, color: Colors.white, ), ), ), ); },),),); } @override voiddispose() {
    controller?.dispose();
    super.dispose();
  }
}

Copy the code