Flutter笔记--动画

 Flutter动画

  Flutter动画,从Android角度理解,它属于是属性动画,因为它是对控件的属性做操作。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添加“动画状态改变”监听器;动画开始、结束、正向或反向时会调用状态改变的监听器。

Curve

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

AnimationController
AnimationController用于控制动画,它包含动画的启动forward()、停止stop() 、反向播放 reverse()等方法。AnimationController会在动画的每一帧,就会生成一个新的值。默认情况下,AnimationController在给定的时间段内线性的生成从0.0到1.0(默认区间)的数字。AnimationController派生自Animation<double>,因此可以在需要Animation对象的任何地方使用。 但是,AnimationController具有控制动画的其他方法,例如forward()方法可以启动正向动画,reverse()可以启动反向动画。duration表示动画执行的时长,通过它我们可以控制动画的速度。

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生成[-100.0,0.0]的值:

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

        Tween构造函数需要begin和end两个参数。Tween的唯一职责就是定义从输入范围到输出范围的映射。输入范围通常为[0.0,1.0],但这不是必须的,我们可以自定义需要的范围。Tween继承自Animatable<T>,而不是继承自Animation<T>,Animatable中主要定义动画值的映射规则。

Tween.animate
要使用Tween对象,需要调用其animate()方法,然后传入一个控制器对象。

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

来看一个小栗子:

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

class AnimationPage extends StatefulWidget {

  @override
  State<StatefulWidget> createState() {
    return AnimationDetail();
  }
}

class AnimationDetail extends State<AnimationPage> with SingleTickerProviderStateMixin{

  Animation<double> animation;
  AnimationController controller;

  @override
  void initState() {
    super.initState();
    controller = new AnimationController(
      duration: const Duration(seconds: 2),vsync: this);

    // animation = new Tween(begin: 0.0,end: 300.0).animate(controller)
    // ..addListener(() { setState(() {
    //
    // });
    // });

    //使用弹性曲线
    animation = CurvedAnimation(parent: controller,curve: Curves.bounceIn);
    //图片宽高从0变到300
    animation = new Tween(begin: 0.0,end: 300.0).animate(animation)
    ..addListener(() {setState(() {
        print('------anim-----');
    });
    });

    //启动动画
    controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return
    //   new Center(
    //   child:
    //   Image.asset("images/a.jpeg",
    //   width: animation.value,
    //   height: animation.value,),
    // );

    //2
    // AnimatedBuilder(animation: animation,
    //     child: Image.asset("images/a.jpeg"),
    //     builder: (BuildContext ctx,Widget child) {
    //       return new Center(
    //         child: Container(
    //           height: animation.value,
    //           width: animation.value,
    //           child: child,
    //         ),
    //       );
    //     });

    // 3
    AnimatedImage(animation: animation,);

  }

  @override
  void dispose() {
    // TODO: implement dispose
    controller.dispose();
    super.dispose();
  }
}

class AnimatedImage extends AnimatedWidget {

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

  @override
  Widget build(BuildContext context) {
    final Animation<double> animation = listenable;
    return new Center(
      child: Image.asset("images/a.jpeg",
      width: animation.value,
        height: animation.value,
      ),
    );
  }
}

猜你喜欢

转载自blog.csdn.net/ljt2724960661/article/details/109967484
今日推荐