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();
  }
}

猜你喜欢

转载自blog.csdn.net/weixin_33716557/article/details/87217036