fullter

Flutter 动画基础

2020-07-15  本文已影响0人  望穿秋水小作坊
Flutter 动画基础

一:使用 AnimationController 实现缩放动画


class ScaleAnimationRoute extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _ScaleAnimationRouteState();
  }
}

// 需要继承 TickerProvider , 如果有多个 AnimationController,则应该使用 TickerProviderStateMixin
class _ScaleAnimationRouteState extends State<ScaleAnimationRoute>
    with SingleTickerProviderStateMixin {
  Animation<double> animation;

  @override
  void initState() {
    super.initState();

    // 这个家伙独立就可以完成整个动画
    controller = new AnimationController(
        vsync: this,
        duration: const Duration(seconds: 1),
        lowerBound: 10.0,
        upperBound: 400.0)
      ..addListener(() {
        setState(() => {});
      });

    // 启动动画(正向执行)
    controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Image.asset(
      "images/avatar.jpg",
      width: controller.value,
      height: controller.value,
    );
  }

  @override
  void dispose() {
    // 需要进行释放,以免内存泄露
    controller.dispose();
    super.dispose();
  }
}

二:使用 AnimationController + CurvedAnimation + Tween 实现缩放动画

// 需要继承 TickerProvider , 如果有多个 AnimationController,则应该使用 TickerProviderStateMixin
class _ScaleAnimationRouteState extends State<ScaleAnimationRoute>
    with SingleTickerProviderStateMixin {
  AnimationController controller;
  CurvedAnimation curvedAnimation;
  Animation<double> animation;

  @override
  void initState() {
    super.initState();

    controller = new AnimationController(
        duration: const Duration(seconds: 3), vsync: this);

    curvedAnimation =
        CurvedAnimation(parent: controller, curve: Curves.decelerate);

    // 图片宽高从 0 变到 300
    animation = new Tween(begin: 0.0, end: 300.0).animate(curvedAnimation)
      ..addListener(() {
        setState(() => {});
      });

    // 启动动画(正向执行)
    controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Image.asset(
      "images/avatar.jpg",
      width: animation.value,
      height: animation.value,
    );
  }

  @override
  void dispose() {
    // 需要进行释放,以免内存泄露
    controller.dispose();
    super.dispose();
  }
}

三:使用 AnimatedBuilder 重构

class ScaleAnimationRoute extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _ScaleAnimationRouteState();
  }
}

// 需要继承 TickerProvider , 如果有多个 AnimationController,则应该使用 TickerProviderStateMixin
class _ScaleAnimationRouteState extends State<ScaleAnimationRoute>
    with SingleTickerProviderStateMixin {
  AnimationController controller;
  CurvedAnimation curvedAnimation;
  Animation<double> animation;

  @override
  void initState() {
    super.initState();

    controller = new AnimationController(
        duration: const Duration(seconds: 3), vsync: this);

    curvedAnimation =
        CurvedAnimation(parent: controller, curve: Curves.decelerate);

    // 图片宽高从 0 变到 300
    animation = new Tween(begin: 0.0, end: 300.0).animate(curvedAnimation);

    // 启动动画(正向执行)
    controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return GrowTransition(
      child: Image.asset("images/333.jpg"),
      animation: animation,
    );
  }

  @override
  void dispose() {
    // 需要进行释放,以免内存泄露
    controller.dispose();
    super.dispose();
  }
}

class GrowTransition extends StatelessWidget {
  GrowTransition({this.child, this.animation});
  final Widget child;
  final Animation<double> animation;

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

优点

  1. 不用显式的去添加帧监听器,然后再调用 setState() 了,这个好处和 AnimatedWidget 是一样的。
  2. 动画构建的范围缩小了,如果没有 Builder,setState()将会在父组件上下文中调用,这将会导致父组件的 build 方法重新调用;而有了 builder 之后,只会导致动画 widget 自身的 build 重新调用,避免不必要的 rebuild。
  3. 通过 AnimatedBuilder 可以封装常见的过渡效果来复用动画。

四:让动画永动起来。

initState() {
    super.initState();
    controller = new AnimationController(
        duration: const Duration(seconds: 1), vsync: this);
    //图片宽高从0变到300
    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();
  }

循环动画,这种动画效果,我们只需要监听动画状态改变即可。

上一篇 下一篇

猜你喜欢

热点阅读