精华内容
参与话题
问答
  • Flutter 动画

    2019-12-04 17:48:19
    Animation:Flutter动画库中的一个核心类,它生成指导动画的值。 AnimationController:管理Animation。 Tween:用来定义动画的执行区间。例如,Tween可能会生成从红到蓝之间的色值,或者从0到255。 ...

    一、基本的动画概念和类

    • Animation:Flutter动画库中的一个核心类,它生成指导动画的值。
    • AnimationController:管理Animation。
    • Tween:用来定义动画的执行区间。例如,Tween可能会生成从红到蓝之间的色值,或者从0到255。
    • CurvedAnimation:定义一个非线性曲线的动画.
    • Listeners:监听动画的运行过程。
    • StatusListeners:监听动画状态改变。

    1、Animation

    Animation对象是指在规定时间和区间内生成动画值的类。Animation对象的输出可以是线性的、曲线的、一个步进函数或者任何其他可以设计的映射。 根据Animation对象的控制方式,动画可以反向运行,甚至可以在中间切换方向。

    Animation 生成的类型值很多,如:Animation<double>、Animation<Color> 、 Animation<Size>等。

    Animation对象有状态。可以通过(value)属性获取动画的当前值,(isCompleted)判断动画是否完成,(isDismissed)判断动画是否在开始时停止动画

    Animation对象本身和UI渲染没有任何关系。

    2、AnimationController

    AnimationController是一个较为特殊的Animation对象,用来控制管理Animation。但AnimationController是Animation<double>的子类,因此可以在需要Animation对象的任何地方使用。默认情况下,AnimationController在给定的持续时间内线性生成从0.0到1.0的值。

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

    上述是AnimationController 对象的创建方式,构造函数第一个参数是动画执行的时间,第二个vsync传入是防止动画离屏之后继续消耗资源。AnimationController 提供了几个常用的方法。

    • forward():启动动画;
    • reverse({double from}:倒放动画;
    • reset():重置动画,将其设置到动画的开始位置;
    • stop({ bool canceled = true }):停止动画。

    3、Tween

    默认情况下,AnimationController的区间是0.0到1.0,如果我们需要不同的范围或者不同类型的区间时,就可以使用Tween来设置不同类型的区间范围。Tween是一个无状态(stateless)对象,需要beginend值。Tween的唯一职责就是定义从开始到结束区间的映射。如颜色区间映射范围:

    final Tween<Color> doubleTween = new Tween(begin: Colors.red, end: Colors.blue);

    Tween继承自Animatable<T>。Tween对象不存储任何状态,但它提供了一下方法:

    • T evaluate(Animation<double> animation):方法将映射函数应用于动画当前值。
    • Animation<T> animate(Animation<double> parent):需要传入一个控制器,来获取Animation对象。

    4、CurvedAnimation

    CurvedAnimation 将动画过程定义为一个非线性曲线,其创建方式如下:

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

    parent:参数为需要传入的控制器,

    curve:参数为控制动画的非线性曲线,在Curves中已经定义了很多属性,当然我们也可以自定义。

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

    5、Listeners:监听动画的输出过程。

    通过AnimationController对象调用addListener()来实现对动画的输出过程进行监听。 只要动画的值发生变化,就会调用监听器。一个Listener最常见的行为是调用setState()来触发UI重建。

    6、StatusListeners:监听动画状态改变。

    通过AnimationController对象调用addStatusListener()来实现对动画的状态进行监听。比如动画开始、结束、向前移动或向后移动时会调用StatusListener。

     

    二、基础动画实现 

    前面已经介绍了基本动画的类和属性,那么我们来看一下平移、旋转、透明、缩放这些基础动画如何实现。

    1、平移动画

    通过SlideTransition来实现平移动画,附上代码
    class Translate extends StatefulWidget {
      @override
      createState() => TranslateState();
    }
    class TranslateState extends State<Translate> with TickerProviderStateMixin {
      AnimationController controller;
      Animation<Offset> animation;
      @override
      void initState() {
        // TODO: implement initState
        super.initState();
        controller = AnimationController(vsync: this, duration: Duration(seconds: 2));
        controller.addStatusListener((status) {
          if (controller.isCompleted) {
            controller.reverse();
          } else if (controller.isDismissed) {
            controller.forward();
          }
        });
        animation = Tween(begin: Offset.zero, end: Offset(3.0, 0)).animate(controller);
        controller.forward();
      }
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return Container(
          alignment: Alignment.topLeft,
          decoration: BoxDecoration(border: Border.all(color: Colors.black,width: 2)),
          padding: EdgeInsets.all(10),
          height: 100,
          child: SlideTransition(
            position: animation,
            child: new Container(  width: 80, height: 80, color: Colors.red),
          ),
        );
      }
    }

    2、旋转动画

    通过RotationTransition实现旋转动画,附上代码

    class Rotation extends StatefulWidget {
      @override
      createState() => RotationState();
    }
    class RotationState extends State<Rotation>
        with SingleTickerProviderStateMixin {
      AnimationController controller;
      Animation<double> rotation;
      @override
      void initState() {
        // TODO: implement initState
        super.initState();
        controller = new AnimationController(vsync: this, duration: Duration(seconds: 2));
        controller.addStatusListener((state) {
          if (controller.isCompleted) {
            controller.reverse();
          } else if (controller.isDismissed) {
            controller.forward();
          }
        });
        rotation = new Tween(begin: 1.0, end: 0.1).animate(controller);
        controller.forward();
      }
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return Container(
          alignment: Alignment.center,
          decoration: BoxDecoration(border: Border.all(color: Colors.black,width: 2)),
          padding: EdgeInsets.all(10),
          height: 100,
          child: RotationTransition(
            turns: rotation,
            child: new Container( width: 80, height: 80, color: Colors.red, ),
          ),
        );
      }
    }

    3、透明动画

    通过FadeTransition实现透明动画

    class Alpha extends StatefulWidget {
      @override
      createState() => AlphaState();
    }
    class AlphaState extends State<Alpha> with SingleTickerProviderStateMixin {
      AnimationController controller;
      Animation<double> alpha;
      @override
      void initState() {
        super.initState();
        controller = new AnimationController(vsync: this, duration: Duration(seconds: 2));
        controller.addStatusListener((state) {
          if (controller.isCompleted) {
            controller.reverse();
          } else if (controller.isDismissed) {
            controller.forward();
          }
        });
        alpha = new Tween(begin: 1.0, end: 0.5).animate(controller);
        controller.forward();
      }
      @override
      Widget build(BuildContext context) {
        return Container(
          alignment: Alignment.center,
          decoration: BoxDecoration(border: Border.all(color: Colors.black,width: 2)),
          padding: EdgeInsets.all(10),
          child: FadeTransition(
            opacity: alpha,
            child: new Container( width: 100, height: 100, color: Colors.deepPurpleAccent),
          ),
        );
      }
    }

    4、缩放动画

    通过ScaleTransition实现缩放动画

    class Scale extends StatefulWidget {
      @override
      createState() => ScaleState();
    }
    class ScaleState extends State<Scale> with SingleTickerProviderStateMixin {
      AnimationController controller;
      Animation<double> scale;
      @override
      void initState() {
        super.initState();
        controller = new AnimationController(
            vsync: this, duration: Duration(seconds: 2));
        controller.addStatusListener((state){
          if (controller.isCompleted) {
            controller.reverse();
          } else if (controller.isDismissed) {
            controller.forward();
          }
        });
        scale = new Tween(begin: 1.0,end: 0.1).animate(controller);
        controller.forward();
      }
    
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return Container(
          alignment: Alignment.center,
          decoration: BoxDecoration(border: Border.all(color: Colors.black,width: 2)),
          padding: EdgeInsets.all(10),
          height: 100,
          child: new ScaleTransition(
            scale: scale,
            child: new Container( width: 80, height: 80, color: Colors.red, ),
          ),
        );
      }
    }

    实现效果:

                 

     

    三、并行动画和串行动画的实现:

    1、并行动画

    并行动画是指两个及两个以上的动画同时运行。

    例如:视图在平移的同时视图从矩形变成圆形。

    class Parallel extends StatefulWidget {
      @override
      State<StatefulWidget> createState() {
        // TODO: implement createState
        return ParallelDemoState();
      }
    }
    class ParallelDemoState extends State<Parallel> with SingleTickerProviderStateMixin {
      Tween<double> slideTween = Tween(begin: 0.0, end: 300.0);
      Tween<double> borderTween = Tween(begin: 0.0, end: 40.0); // 添加边角半径变动范围
      Animation<double> slideAnimation;
      Animation<double> borderAnimation; // 添加边角半径动画定义
      AnimationController controller;
      @override
      void initState() {
        controller = AnimationController(duration: Duration(seconds: 2), vsync: this);
        slideAnimation = slideTween.animate(CurvedAnimation(parent: controller, curve: Curves.decelerate));
        borderAnimation = borderTween.animate(CurvedAnimation(parent: controller, curve: Curves.linear)); // 定义边角半径动画
    
        controller.addStatusListener((state) {
          double dd = slideAnimation.value;
          if (controller.isCompleted) {
            controller.reverse();
          } else if (controller.isDismissed) {
            controller.forward();
          }
        });
        controller.addListener((){
          setState(() {
    
          });
        });
        controller.forward();
      }
    
      @override
      Widget build(BuildContext context) {
        return Container(
          alignment: Alignment.topLeft,
          decoration: BoxDecoration(border: Border.all(color: Colors.black,width: 2)),
          padding: EdgeInsets.all(10),
          width: 200,
          child: Container(
            margin: EdgeInsets.only(left: slideAnimation.value),
            width: 80,
            height: 80,
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(borderAnimation.value),
              color: Colors.blue,
            ),
           
          ),
        );
      }
    }
    

    2、串行动画

    串行动画是指动画一个接一个的执行。

    例如:动画平移之后在从矩形变成圆形。

    class Sequential extends StatefulWidget {
      @override
      createState() => SequentialState();
    }
    
    class SequentialState extends State<Sequential> with SingleTickerProviderStateMixin {
      AnimationController controller;
      Tween<double> slideTween = Tween(begin: 0.0, end: 200.0);
      Tween<double> borderTween = Tween(begin: 0.0, end: 40.0); // 添加边角半径变动范围
      Animation<double> slideAnimation;
      Animation<double> borderAnimation;
    
      @override
      void initState() {
        controller =
            AnimationController(duration: Duration(seconds: 2), vsync: this);
        slideAnimation = slideTween.animate(  CurveTween(curve: Interval(0.0, 0.5, curve: Curves.linear)).animate(controller));
        borderAnimation = borderTween.animate(CurveTween(curve: Interval(0.5, 1.0, curve: Curves.linear)).animate(controller));
        controller.addStatusListener((state) {
          if (controller.isCompleted) {
            controller.reverse();
          } else if (controller.isDismissed) {
            controller.forward();
          }
        });
        controller.addListener((){
          setState(() {
          });
        });
        controller.forward();
      }
    
      @override
      Widget build(BuildContext context) {
        return Container(
          padding: EdgeInsets.all(10),
          decoration: BoxDecoration(
            border: Border.all(color: Colors.black, width: 2),
          ),
          alignment: Alignment.centerLeft,
          child: Container(
            width: 80,
            height: 80,
            margin: EdgeInsets.only(left: slideAnimation.value),
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(borderAnimation.value),
              // 边角半径的属性上添加动画
              color: Colors.blue,
            ),
          ),
        );
      }
    }
    

    效果图:

                    

     

    展开全文
  • flutter 动画

    2019-05-15 12:23:00
    AnimatedCrossFade AnimatedCrossFade让俩个子widget 交替淡入淡出。 class AnimatedCrossFade1 extends StatefulWidget { @override State<StatefulWidget>... // TODO: implement createSt...
    AnimatedCrossFade

    AnimatedCrossFade让俩个子widget 交替淡入淡出。

    class AnimatedCrossFade1 extends StatefulWidget {
      @override
      State<StatefulWidget> createState() {
        // TODO: implement createState
        return new AnimatedCrossFade2();
      }
    }
    
    class AnimatedCrossFade2 extends State<AnimatedCrossFade1> {
      var _first = false;
    
      @override
      Widget build(BuildContext context) {
        new Timer(new Duration(seconds: 3), () {
          setState(() {
            _first = !_first;
          });
        });
        return AnimatedCrossFade(
          duration: const Duration(seconds: 3),
          firstChild:
              const FlutterLogo(style: FlutterLogoStyle.horizontal, size: 100.0),
          secondChild:
              const FlutterLogo(style: FlutterLogoStyle.stacked, size: 100.0),
          crossFadeState:
              _first ? CrossFadeState.showFirst : CrossFadeState.showSecond,
        );
      }
    }
    

      

    AnimatedBuilder

    AnimatedBuilder构建动画最常用的控件。AnimatedBuilder 由 animation,child,builder 三个参数。

    class AnimatedBuilder1 extends StatefulWidget {
      @override
      State<StatefulWidget> createState() {
        return new AnimatedBuilder2();
      }
    }
    class AnimatedBuilder2 extends State<AnimatedBuilder1>
        with SingleTickerProviderStateMixin {
      @override
      Widget build(BuildContext context) {
        var controller =
            AnimationController(duration: Duration(seconds: 3), vsync: this)
              ..forward();
    
        return new AnimatedBuilder(
            animation: controller,
            child: Container(width: 200.0, height: 200.0, color: Colors.green),
            builder: (BuildContext context, Widget child) {
              print(controller.value);
              return Transform.scale(
                scale: controller.value,
                child: child,
              );
            });
      }
    }
    

      

    当创建一个AnimationController时,需要传递一个vsync参数,存在vsync时会防止屏幕外动画(译者语:动画的UI不在当前屏幕时)消耗不必要的资源。 通过将SingleTickerProviderStateMixin添加到类定义中,可以将stateful对象作为vsync的值。你可以在GitHub的animate1中看到这个例子 。

    2.3 DecoratedBoxTransition

    DecoratedBoxTransition 装饰widget边界的动画。核心是Animation<Decoration>对象和Child。Animation<Decoration>通过DecorationTween.animate(controller) 得到。

    属性:position 代表绘制边框是在widget前还是后。

    demo如下:

    class DecoratedBoxTransition1 extends StatefulWidget {
      @override
      State<StatefulWidget> createState() {
        return new DecoratedBoxTransition2();
      }
    }
    
    class DecoratedBoxTransition2 extends State<DecoratedBoxTransition1>
        with SingleTickerProviderStateMixin {
      @override
      Widget build(BuildContext context) {
        DecorationTween decorationTween = DecorationTween(
          begin: BoxDecoration(
            color: Colors.blue,//子widget背景颜色
            border: Border.all(
              color: Colors.blue,//边界颜色
              style: BorderStyle.solid,
              width: 1.0,
            ),
            borderRadius: BorderRadius.all(Radius.circular(20)),
            shape: BoxShape.rectangle,
            boxShadow: const <BoxShadow>[
              BoxShadow(
                color: Colors.amberAccent,
                blurRadius: 5.0,
                spreadRadius: 5.0,
              )
            ],
          ),
          end: BoxDecoration(
            color: Colors.green,
            border: Border.all(
              color: Colors.green,
              style: BorderStyle.solid,
              width: 1.0,
            ),
            shape: BoxShape.rectangle,
            boxShadow: const <BoxShadow>[
              BoxShadow(
                color: Colors.blueGrey,
                blurRadius: 5.0,
                spreadRadius: 5.0,
              )
            ],
            borderRadius: BorderRadius.all(Radius.circular(30)),
          ),
        );
        var controller =
            AnimationController(duration: Duration(seconds: 3), vsync: this)
              ..forward();
        Animation<Decoration> d = decorationTween.animate(controller);
        return new DecoratedBoxTransition(
            decoration: d,
            position: DecorationPosition.background,
            child: new Container(
              width: 200,
              height: 200,
            ));
      }
    }
    

      

    ps: DecoratedBoxTransition 的child 背景色最好是无色的。不然会影响效果

    2.3 FadeTransition 淡入淡出动画

    FadeTransition 淡入淡出动画。opacity 属性需要指定一个Animation<double>,child属性指定widget。


    @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Center(
            child: new FadeTransition(
              opacity: new AnimationController(
                duration: Duration(seconds: 3),
                vsync: this,
              )..repeat(),
              child: FlutterLogo(style: FlutterLogoStyle.horizontal, size: 100.0),
              alwaysIncludeSemantics: true,
            ),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: _incrementCounter,
            tooltip: 'Increment',
            child: Icon(Icons.add),
          ), // This trailing comma makes auto-formatting nicer for build methods.
        );
      }
    

      

    2.4 PositionedTransition 定位动画

    PositionedTransition动画很麻烦,主要由俩个重要的属性:

    • rect
      规定子widget 离 Stack边距的值。由RelativeRectTween.animate(AnimationController)获得。
    • child
      顾名思义将被施加动画的widget
    ps:PositionedTransition 必须作为Stack 控件的子View,否则就会报错。
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
    
      final String title;
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin{
      @override
      Widget build(BuildContext context) {
    
        Animatable animatable= RelativeRectTween(begin: new RelativeRect.fromLTRB(75.0, 75, 75, 75.0),
        end: new RelativeRect.fromLTRB(100.0, 100.0, 100.0, 100.0),
    );
        Animation frontRelativeRect = animatable.animate(new AnimationController(
          duration: Duration(seconds: 3),
          vsync: this,
        )..repeat());
    
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Stack(
           alignment: Alignment.center,
           fit: StackFit.loose,
            children: <Widget>[
          
             Container(
              width: 200,
              height: 200,
              color: Colors.blue),
            Container(
              width: 100,
              height: 100,
              color: Colors.red,
            ),
    
              PositionedTransition(
              rect: frontRelativeRect,
              child:        Container(
              width: 50,
              height: 50,
              color: Colors.orange,
            ) ,
            )
            ],
          ), // This trailing comma makes auto-formatting nicer for build methods.
        );
      }
    }
    

      

    Stack 控件

    Stack层叠控件。其childWidget 可以层叠到一起,层叠顺序:Widget越后创建,层级越靠上
    可以控制没有定位的childWidget的布局策略。
    可以控制没有定位的childWidget的布局策略

    Stack({
      this.alignment = AlignmentDirectional.topStart,
      this.textDirection,
      this.fit = StackFit.loose,
      this.overflow = Overflow.clip,
      List<Widget> children = const <Widget>[],
    })
    

      

    • alignment
      决定如何去对齐没有定位(没有使用Positioned)或部分定位的子widget。所谓部分定位,在这里特指没有在某一个轴上定位:left、right为横轴,top、bottom为纵轴,只要包含某个轴上的一个定位属性就算在该轴上有定位

    • textDirection
      和Row、Wrap的textDirection功能一样,都用于决定alignment对齐的参考系即:textDirection的值为TextDirection.ltr,则alignment的start代表左,end代表右;textDirection的值为TextDirection.rtl,则alignment的start代表右,end代表左。

    • fit
      此参数用于决定没有定位的子widget如何去适应Stack的大小。StackFit.loose表示使用子widget的大小,StackFit.expand表示扩伸到Stack的大小。

    • overflow
      此属性决定如何显示超出Stack显示空间的子widget,值为Overflow.clip时,超出部分会被剪裁(隐藏),值为Overflow.visible 时则不会。

    2.5 RotationTransition 旋转动画

    旋转动画RotationTransition。核心属性child和turns。

    class RotationTransitionState extends State<RotationTransition1> with SingleTickerProviderStateMixin  {
      @override
      Widget build(BuildContext context) {
        return new RotationTransition(
          child: Container(
            width: 100,
            height: 100,
            color: Colors.orange,
          ),
          turns: AnimationController(
            duration: Duration(seconds: 1),
            vsync: this,
            lowerBound: 0,
            upperBound: 0.1,
          )..forward(),
        );
      }
    }
    

      

    2.6 ScaleTransition缩放动画

    ScaleTransition 核心属性child 和scale。scale类型是Animation<double>。Animation<double>可以根据Tween.animate 生成。
    demo:是由1缩小到0

    class ScaleTransitionState extends State<ScaleTransition1>
        with SingleTickerProviderStateMixin {
      @override
      Widget build(BuildContext context) {
        Animation<double> t =
            Tween(begin: 1.0, end: 0.0).animate(AnimationController(
          duration: Duration(seconds: 3),
          vsync: this,
        )..forward());
    
        return new ScaleTransition(
          child: Container(
            width: 100,
            height: 100,
            color: Colors.orange,
          ),
          scale: t,
        );
      }
    }
    

      

    2.6 SlideTransition移动动画

    SlideTransition 动画最重要的属性是position和child。position是Animation<Offset>。可以通过Tween.animate 生成。

    class SlideTransition1State extends State<SlideTransition1>
        with SingleTickerProviderStateMixin {
      @override
      Widget build(BuildContext context) {
        var t = Tween<Offset>(
          begin: const Offset(0.0, 2.0),
          end: const Offset(0.0, 1.0),
        ).animate(AnimationController(
          duration: Duration(seconds: 3),
          vsync: this,
        )..forward());
    
        return new SlideTransition(
          child: Container(
            width: 100,
            height: 100,
            color: Colors.orange,
          ),
          position: t,
        );
      }
    }
    

      

    begin: const Offset(0.0, 2.0)表示的意思是:动画刚开始child的x轴的起点不变,y轴起点是(1+2)* y。ps:y是child的高度值
    end: const Offset(0.0, 1.0) 表示的意思是:动画结束后,x轴坐标不变,y轴坐标是(1+1)* y

    转载于:https://www.cnblogs.com/pythonClub/p/10868718.html

    展开全文
  • flutter动画

    2020-04-17 11:29:18
    flutter动画本质就是自动生成一个线性的值,生成的间隔 和时间 控制动画的效果, 官网动画直通车这里面有教你写几个简单的小栗子 可以使用Tween来配置动画以生成不同的范围或数据类型的值,比如: final Tween ...

    flutter线性动画

    flutter动画本质就是自动生成一个线性的值,生成的间隔 和时间 控制动画的效果,
    官网动画直通车这里面有教你写几个简单的小栗子
    可以使用Tween来配置动画以生成不同的范围或数据类型的值,比如:

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

    Tween对象不存储任何状态。相反,它提供了evaluate(Animation animation)方法将映射函数应用于动画当前值。 Animation对象的当前值可以通过value()方法取到。evaluate函数还执行一些其它处理,例如分别确保在动画值为0.0和1.0时返回开始和结束状态。

    controller = AnimationController(
            duration: const Duration(milliseconds: 1000), vsync: this);
        curve = new CurvedAnimation(parent: controller, curve: Curves.easeInSine);
        animation = Tween<double>(begin: st, end: ed).animate(curve);
        animation.addListener((){
          setState(() {});
          print(animation.value);
        }) ;
    

    也就是说Tween的.animate方法,传给他动画控制器和线性会返回一个Animation对象。
    vsync: this动画的不在当前屏幕时,就不需要消耗不必要的资源
    curve可以自定义 也可以用官网写好的常用线性效果

    这有个点击旋转的例子,可以参考:

    在这里插入图片描述

    import 'dart:math' as math;
    import 'package:flutter/material.dart';
    import 'package:charts_flutter/flutter.dart' as charts;
    import 'package:flutter_animation/demo/animation.dart';
    
    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 Animation',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: MyHomePage(),
        );
      }
    }
    
    //AnimatedWidget(基类)中会自动调用addListener()和setState()。
    class AnimatedBox extends AnimatedWidget {
      Widget build(BuildContext context) {
        final Animation<double> animation = listenable;
        return Center(
          child: Text('s'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class LinearSales {
      final int year;
      final int sales;
      LinearSales(this.year, this.sales);
    }
    
    class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
      static double st = 0.0;
      static double ed = 0.0; 
      double an = 0.0;
      DragDownDetails  point;
    
      // static final _tween = new Tween<double>(begin: st, end: ed);
      Animation doubleTween;
    
      AnimationController controller;
      Animation<double> animation;
      Animation curve;
    
      initState() {
        super.initState();
        controller = AnimationController(
            duration: const Duration(milliseconds: 1000), vsync: this);
        curve = new CurvedAnimation(parent: controller, curve: Curves.easeInSine);
        animation = Tween<double>(begin: st, end: ed).animate(curve);
        animation.addListener((){
          setState(() {});
        }) ;
      }
    
    //传度数返回角度
      angle(double angle) {
        return (math.pi / 180) * angle;
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
              title: Text('en'),
            ),
            body: GestureDetector(
              child: Transform.rotate(
                angle: angle(animation.value),
                child: Charts.create(),
              ),
              onPanUpdate: (details) {
                // double x = details.localPosition.dx;
                // double y = details.localPosition.dy;
                // setState(() {
                //   //两点坐标与中点的(180,350)夹角
                // an = math.atan2(x-180,350-y)/math.pi*180;
                // });
              },
              onPanDown: (details) {
                point = details;
                print(point);
                setState(() {
                  ed = ed + 45;
                  animation = Tween<double>(begin: st, end: ed).animate(curve);
                  controller.reset();
                  controller.forward();
                  st = ed;
                });
              },
            ));
      }
      dispose() {
        controller.dispose();
        super.dispose();
      }
    }
    
    class Charts extends StatelessWidget {
      final List<charts.Series> seriesList;
    
      Charts(this.seriesList);
    
      factory Charts.create() {
        return Charts(_createSampleData());
      }
    
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return charts.PieChart(seriesList,
            animate: false,
            defaultRenderer: new charts.ArcRendererConfig(arcRendererDecorators: [
              new charts.ArcLabelDecorator(
                  labelPosition: charts.ArcLabelPosition.outside)
            ]));
      }
    
      static List<charts.Series<DataRow, String>> _createSampleData() {
        final data = [
          new DataRow("1", "A", 123),
          new DataRow("3", "B", 322),
          new DataRow("4", "C", 322),
          new DataRow("5", "D", 322)
        ];
        return [
          new charts.Series<DataRow, String>(
              id: "serId",
              // keyFn: (DataRow dr, _) => dr.id,
              domainFn: (DataRow dr, _) => dr.label,
              measureFn: (DataRow dr, _) => dr.value,
              data: data)
        ];
      }
    }
    
    class DataRow {
      final String id;
      final String label;
      final double value;
      DataRow(this.id, this.label, this.value);
    }
    
    展开全文
  • Flutter动画

    2020-07-30 16:42:25
    Flutter动画抽象 Flutter中也对动画进行了抽象,主要涉及Animation、Curve、Controller、Tween这四个角色,它们一起配合来完成一个完整动画,下面我们一一来介绍它们。 Animation Animation是一个抽象类,它...

    Flutter中动画抽象

    Flutter中也对动画进行了抽象,主要涉及Animation、Curve、Controller、Tween这四个角色,它们一起配合来完成一个完整动画,下面我们一一来介绍它们。

    Animation

    Animation是一个抽象类,它本身和UI渲染没有任何关系,而它主要的功能是保存动画的插值和状态;其中一个比较常用的Animation类是Animation<double>Animation对象是一个在一段时间内依次生成一个区间(Tween)之间值的类。Animation对象在整个动画执行过程中输出的值可以是线性的、曲线的、一个步进函数或者任何其他曲线函数等等,这由Curve来决定。 根据Animation对象的控制方式,动画可以正向运行(从起始状态开始,到终止状态结束),也可以反向运行,甚至可以在中间切换方向。Animation还可以生成除double之外的其他类型值,如:Animation<Color> 或Animation<Size>。在动画的每一帧中,我们可以通过Animation对象的value属性获取动画的当前状态值。

    动画通知

    我们可以通过Animation来监听动画每一帧以及执行状态的变化,Animation有如下两个方法:

    1. addListener();它可以用于给Animation添加帧监听器,在每一帧都会被调用。帧监听器中最常见的行为是改变状态后调用setState()来触发UI重建。
    2. addStatusListener();它可以给Animation添加“动画状态改变”监听器;动画开始、结束、正向或反向(见AnimationStatus定义)时会调用状态改变的监听器。

    读者在此只需要知道帧监听器和状态监听器的区别,在后面的章节中我们将会举例说明。

    Curve

    动画过程可以是匀速的、匀加速的或者先加速后减速等。Flutter中通过Curve(曲线)来描述动画过程,我们把匀速动画称为线性的(Curves.linear),而非匀速动画称为非线性的。

    我们可以通过CurvedAnimation来指定动画的曲线,如:

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

    CurvedAnimationAnimationController(下面介绍)都是Animation<double>类型。CurvedAnimation可以通过包装AnimationControllerCurve生成一个新的动画对象 ,我们正是通过这种方式来将动画和动画执行的曲线关联起来的。我们指定动画的曲线为Curves.easeIn,它表示动画开始时比较慢,结束时比较快。 Curves 类是一个预置的枚举类,定义了许多常用的曲线,下面列几种常用的:

    Curves曲线 动画过程
    linear 匀速的
    decelerate 匀减速
    ease 开始加速,后面减速
    easeIn 开始慢,后面快
    easeOut 开始快,后面慢
    easeInOut 开始慢,然后加速,最后再减速

    除了上面列举的, Curves 类中还定义了许多其它的曲线,在此便不一一介绍,读者可以自行查看Curves类定义。

    当然我们也可以创建自己Curve,例如我们定义一个正弦曲线:

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

    AnimationController

    AnimationController用于控制动画,它包含动画的启动forward()、停止stop() 、反向播放 reverse()等方法。AnimationController会在动画的每一帧,就会生成一个新的值。默认情况下,AnimationController在给定的时间段内线性的生成从0.0到1.0(默认区间)的数字。 例如,下面代码创建一个Animation对象(但不会启动动画):

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

    AnimationController生成数字的区间可以通过lowerBoundupperBound来指定,如:

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

    AnimationController派生自Animation<double>,因此可以在需要Animation对象的任何地方使用。 但是,AnimationController具有控制动画的其他方法,例如forward()方法可以启动正向动画,reverse()可以启动反向动画。在动画开始执行后开始生成动画帧,屏幕每刷新一次就是一个动画帧,在动画的每一帧,会随着根据动画的曲线来生成当前的动画值(Animation.value),然后根据当前的动画值去构建UI,当所有动画帧依次触发时,动画值会依次改变,所以构建的UI也会依次变化,所以最终我们可以看到一个完成的动画。 另外在动画的每一帧,Animation对象会调用其帧监听器,等动画状态发生改变时(如动画结束)会调用状态改变监听器。

    duration表示动画执行的时长,通过它我们可以控制动画的速度。

    注意: 在某些情况下,动画值可能会超出AnimationController的[0.0,1.0]的范围,这取决于具体的曲线。例如,fling()函数可以根据我们手指滑动(甩出)的速度(velocity)、力量(force)等来模拟一个手指甩出动画,因此它的动画值可以在[0.0,1.0]范围之外 。也就是说,根据选择的曲线,CurvedAnimation的输出可以具有比输入更大的范围。例如,Curves.elasticIn等弹性曲线会生成大于或小于默认范围的值。

    Ticker

    当创建一个AnimationController时,需要传递一个vsync参数,它接收一个TickerProvider类型的对象,它的主要职责是创建Ticker,定义如下:

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

    Flutter应用在启动时都会绑定一个SchedulerBinding,通过SchedulerBinding可以给每一次屏幕刷新添加回调,而Ticker就是通过SchedulerBinding来添加屏幕刷新回调,这样一来,每次屏幕刷新都会调用TickerCallback。使用Ticker(而不是Timer)来驱动动画会防止屏幕外动画(动画的UI不在当前屏幕时,如锁屏时)消耗不必要的资源,因为Flutter中屏幕刷新时会通知到绑定的SchedulerBinding,而Ticker是受SchedulerBinding驱动的,由于锁屏后屏幕会停止刷新,所以Ticker就不会再触发。

    通常我们会将SingleTickerProviderStateMixin添加到State的定义中,然后将State对象作为vsync的值,这在后面的例子中可以见到。

    Tween

    默认情况下,AnimationController对象值的范围是[0.0,1.0]。如果我们需要构建UI的动画值在不同的范围或不同的数据类型,则可以使用Tween来添加映射以生成不同的范围或数据类型的值。例如,像下面示例,Tween生成[-200.0,0.0]的值:

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

    Tween构造函数需要beginend两个参数。Tween的唯一职责就是定义从输入范围到输出范围的映射。输入范围通常为[0.0,1.0],但这不是必须的,我们可以自定义需要的范围。

    Tween继承自Animatable<T>,而不是继承自Animation<T>Animatable中主要定义动画值的映射规则。

    下面我们看一个ColorTween将动画输入范围映射为两种颜色值之间过渡输出的例子:

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

    Tween对象不存储任何状态,相反,它提供了evaluate(Animation<double> animation)方法,它可以获取动画当前映射值。 Animation对象的当前值可以通过value()方法取到。evaluate函数还执行一些其它处理,例如分别确保在动画值为0.0和1.0时返回开始和结束状态。

    Tween.animate

    要使用Tween对象,需要调用其animate()方法,然后传入一个控制器对象。例如,以下代码在500毫秒内生成从0到255的整数值。

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

    注意animate()返回的是一个Animation,而不是一个Animatable

    以下示例构建了一个控制器、一条曲线和一个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);

    参考文章:https://book.flutterchina.club/chapter9/intro.html
    Flutter-动画(平移/缩放/旋转/Alpha)https://www.jianshu.com/p/ee243d5d0a41 

    展开全文
  • Flutter动画基础教程

    千人学习 2019-08-25 19:40:24
    Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的用户界面。本课程以理论+实例的方式带领大家学习动画的基础理论及各种动画特效的编写。 本次课程包含以下内容: 动画基本概念 动画的本质...
  • 不要急躁,开始的我和你是一样的,第一遍看完,完全不知道在说什么,不明白不要紧,请先收藏此文章,然后先去学习下Flutter内置的25种动画组件。 地址:http://laomengit.com/flutter/module/animated_1/。 不要仅仅...
  • Flutter动画explorer

    2019-08-10 05:08:18
    Flutter动画explorer
  • Flutter 动画系列》组合动画

    千次阅读 2020-04-05 17:15:08
    老孟导读:在前面的文章中介绍了 《Flutter 动画系列》25种动画组件...《Flutter 动画系列》Google工程师带你选择Flutter动画控件: http://laomengit.com/flutter/module/animated_choose/ 在项目中动画效果很多...
  • Flutter 动画曲线Curves 效果一览

    千次阅读 多人点赞 2019-07-16 08:57:04
    Curves中一共38中动画曲线,我将文档中提供的MP4转为了GIF。方便大家使用动画时查找使用。 ...
  • 老孟导读:CustomPaint可以称之为动画鼻祖,它可以实现任何酷炫的动画和效果。CustomPaint本身没有动画属性,仅仅是绘制属性,一般情况下,CustomPaint会和动画控制配合使用,达到理想的效果。 基本用法 ...
  • JavaScript开发Flutter动画explorer
  • 文章目录Hero 动画效果示例更多...Flutter 中也提供 相应的 Hero widget 实现该效果。 既然 Hero是个widget,按照惯例,我们来看看构造函数支持哪些字段: const Hero({ Key key, @required this.tag, // 共享元...
  • SizeTransition为尺寸控制动画,其内部核心原理是其child外面包裹着一个Align,然后利用Align的widthFactor和heightFactor的性质,动态的改变父组件的大小,注意是父组件,不是子组件。Flutter之Align和...
  • Flutter 动画

    2019-07-10 22:30:46
    Flutter中的动画分为补间(Tween)动画和基于物理(Physics-based)的动画。 在补间动画中,定义了开始点和结束点、时间线以及定义转换时间和速度的曲线,然后由框架自动计算如何从开始点过渡到结束点。 在基于物理的...
  • Flutter 动画使用

    千次阅读 2018-05-07 23:20:16
    效果预览、 旋转动画 ...在Flutter中,可以通过动画库给widget添加动画。 在Android中,您可以通过XML创建动画或在视图上调用.animate()。在Flutter中,您可以将widget包装到Animation中。...
  • Flutter 动画教程

    2019-07-30 14:52:43
    本教程向您展示如何在Flutter中构建显式动画。在介绍了动画库中的一些基本概念、类和方法之后,它将带您浏览5个动画示例。这些示例相互构建,向您介绍动画库的不同方面。 Flutter SDK还提供了过渡动画,比如...
  • Flutter 动画组件

    2019-05-08 08:33:07
    为 null 的属性,以及 Container 的子孙不会发生动画。 AnimatedContainer 使用内部的 AnimationController,在 Container 的属性中产生简单的、隐式动画。 如果要产生更复杂的动画,可以使用 AnimatedWidget 的子类...
  • Flutter 动画基础

    2019-11-09 18:26:43
    Flutter中的动画系统基于Animation对象的,widget可以在build...flutter动画实现基于AnimationController对象。所以要先定义: AnimationController controller =new AnimationController(duration: const Duration...
  • Flutter动画介绍

    2019-02-27 21:02:57
    文章目录动画Animation的类型补间动画物理动画常见动画...Flutter动画支持使得它更加容易地实现丰富的动画类型。许多widget,特别是在设计规范中就定义了标准的动效的Material widgets,都可以自定义动画效果。 ...
  • Flutter 动画入门

    2019-01-28 01:12:16
    官方动画介绍 让Widget动起来 1.使用Animation 原理类似于Android的属性动画,和Widget分离,在一定时间内生成一系列的值,值可以是int,double,color或者string等等,每隔N毫秒,或者N秒钟获取到最新的值去替换掉...
  • flutter 动画 practice

    2019-05-15 13:56:00
    import 'package:flutter/material.dart'; import 'dart:io'; import 'dart:async'; main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext c...

空空如也

1 2 3 4 5 ... 20
收藏数 1,480
精华内容 592
关键字:

flutter动画