专栏首页三流程序员的挣扎Flutter 学习笔记 15 - 动画 AnimatedBuilder

Flutter 学习笔记 15 - 动画 AnimatedBuilder

之前的例子,build 中使用 Animation 的 value 作为 logo 的宽高,更好的解决方案是将职责分离,logo 的显示只做显示,尺寸的变化应该动画去管理,可以借助 AnimatedBuilder 来完成此分离。

AnimatedBuilder 是渲染树中的一个独立的类。与 AnimatedWidget 类似,自动监听 Animation 的变化,并根据需要将该控件树标记为 dirty 以自动刷新 UI。

看一下它的源码:

class AnimatedBuilder extends AnimatedWidget {

  const AnimatedBuilder({
    Key key,
    @required Listenable animation, // 要做的动画 Animation
    @required this.builder, // 动画 value 变化时调用的函数
    this.child, // 要做动画的 widget
  }) : assert(builder != null),
       super(key: key, listenable: animation);

  // Animation 的 value 变化时会调用 builder 这个函数
  final TransitionBuilder builder;

  final Widget child;

  @override
  Widget build(BuildContext context) {
    return builder(context, child);
  }
}

看 TransitionBuilder 的定义,它是一个函数的别名。

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

现在做动画的 Widget 不再继承 AnimatedWidget 了,本身不管动画怎么处理,不管动画的 value 是多少,只管自己的显示

class LogoWidget extends StatelessWidget { // 无状态
  build(BuildContext context) {
    return Container(
      margin: EdgeInsets.symmetric(vertical: 10.0),
      child: FlutterLogo(), // 显示的 Widget
    );
  }
}

然后要定义一个 AnimatedBuilder 专门处理动画,即它是一个中间件,将 Animation 和要作用的 Widget 关联起来,Animation 和 Widget 本身毫无关联。

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

build 是一个函数,返回一个 Widget。在这里,将要做动画的 Widget 作为 Container 的 child,当参数 animation 的 value 变化时,会重新执行 builder,于是这个 Container 的尺寸就会变化。

现在将它封装到一个 Widget 中

class GrowTransition extends StatelessWidget {
  GrowTransition({this.child, this.animation});

  final Widget child;
  final Animation<double> animation;

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

然后在主 Widget 的 build 方法中直接返回 GrowTransition 即可。

Widget build(BuildContext context) {
  return GrowTransition(child: LogoWidget(), animation: animation);
}

完整的代码如下

class LogoWidget extends StatelessWidget {
  build(BuildContext context) {
    return Container(
      margin: EdgeInsets.symmetric(vertical: 10.0),
      child: FlutterLogo(),
    );
  }
}

class GrowTransition extends StatelessWidget {
  GrowTransition({this.child, this.animation});

  final Widget child;
  final Animation<double> animation;

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

class AnimScreen extends StatefulWidget {
  @override
  _AnimState createState() => _AnimState();
}

class _AnimState extends State<AnimScreen> with SingleTickerProviderStateMixin {
  Animation<double> animation;
  AnimationController controller;

  @override
  initState() {
    super.initState();
    controller = AnimationController(
        duration: const Duration(milliseconds: 2000), vsync: this);
    animation = Tween(begin: 0.0, end: 300.0).animate(controller);
    controller.forward();
  }

  Widget build(BuildContext context) {
    return GrowTransition(child: LogoWidget(), animation: animation);
  }

  dispose() {
    controller.dispose();
    super.dispose();
  }
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Flutter 学习笔记5-构建布局

    使用 Row 水平排列,用 Column 垂直排列。它们都通过 children 添加一个子 widget 列表。

    七适散人
  • Flutter 学习笔记 09 - 路由和导航(1)

    假设已有两个页面 Widget:FirstScreen,SecondScreen。Navigator.push 添加页面,Navigator.pop 弹出页面。

    七适散人
  • Flutter 学习笔记 17 - 交错动画

    多个动画组合在一起,可能有重叠。每个动画对应一个 Tween 对象,一个 AnimationController 控制所有动画。AnimationControl...

    七适散人
  • 【Flutter 专题】60 图解基本 Dialog 对话框小结

    Dialog 在日常开发中应用广泛,大家也对此很熟悉;和尚以前也整理过关于自定义 Dialog 的小博客,今天和尚系统的学习一下最基本的 Dialog;

    阿策
  • CSS3---first-child或者nth-child(1) 不起作用的原因

    一、零碎      1、first-child、last-child、nth-child(n)、nth-child(2n)、nth-child(2n-1)、nt...

    用户1148399
  • 【Flutter 专题】68 图解基本约束 Box (三)

    和尚对约束 Box 探索之路还在继续,和尚今天主要学习一下 Overflow 相关 Box;

    阿策
  • 【Flutter 专题】40 日常小问题小结 (一)

    和尚作为一个小学生在实际操作中遇到很多问题,相对比较常见,和尚来整理记录一下。

    阿策
  • Zuul中聚合Swagger的坑

    每个服务都有自己的接口,通过Swagger来管理接口文档。在服务较多的时候我们希望有一个统一的入口来进行文档的查看,这个时候可以在Zuul中进行文档的聚合显示。

    猿天地
  • 金三银四铜五铁六

    ,以下全文均用LB代替)恰逢是这批面试大军其中的一名小兵,很不幸今年恰逢遇上了互联网寒冬(即各大公司都在裁员,对外提供岗位相对较少的,这意味着很多猿即将面临着更...

    lyb-geek
  • Hadoop vs MPP

    最近我听到了很多关于此话题的讨论。同样,这也是一个大数据领域经验不足的客户非常喜欢提问的问题。实际上,我不喜欢这个含糊不清的词语,但是通常客户会找到我们使用它们...

    smartsi

扫码关注云+社区

领取腾讯云代金券