欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Flutter 动画

程序员文章站 2024-01-14 17:27:16
...

一、基本的动画概念和类

  • 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, ),
      ),
    );
  }
}

实现效果:

             Flutter 动画

 

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

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 动画