Flutter使用AnimatedBuilder实现动效复用

 更新时间:2022年04月02日 11:35:27   作者:岛上码农  
Animation和AnimationWidget都是将组件和动画一起完成的。有些时候,我们只是想动效复用,而不关心组件构建,这个时候就可以使用 AnimatedBuilder了。本文详细讲解了AnimatedBuilder的使用,需要的可以参考一下

前言

我们之前讲述了动画构建的两种方式,Animation 和 AnimationWidget,这两种构建动画都是将组件和动画一起完成的。有些时候,我们只是想动效复用,而不关心组件构建,这个时候就可以使用 AnimatedBuilder 了。

AnimatedBuilder 介绍

根据官方文档说明,AnimatedBuilder 的使用要点如下:

  • An AnimatedBuilder understands how to render the transition. —— AnimatedBuilder 知道如何渲染转场动效。
  • An AnimatedBuilder doesn’t know how to render the widget, nor does it manage the Animation object. —— AnimatedBuilder 不知道(或者准确说不应)如何渲染组件,也不管理组件对象。
  • Use AnimatedBuilder to describe an animation as part of a build method for another widget. If you simply want to define a widget with a reusable animation, use an AnimatedWidget. —— 使用 AnimatedBuilder 作为其他组件的动效描述。如果只是想复用一个带有动效的组件,那么应该使用 AnimatedWidget。这个可以看我们之前关于 AnimatedWidget 的介绍:Flutter 入门与实战(九十四):让你的组件拥有三维动效
  • Examples of AnimatedBuilders in the Flutter API: BottomSheetExpansionTilePopupMenuProgressIndicatorRefreshIndicatorScaffoldSnackBarTabBarTextField. —— 在 Flutter 中,有很多组件使用 AnimatedBuilder 构建动效。

这段话的核心要点就是 AnimatedBuilder 应该只负责动画效果的管理,而不应该管理组件构建。如果混在一起使用,就失去设计者的初衷了。这就好比我们的状态管理和界面一样,一个负责业务逻辑,一个负责界面渲染,从而实现解耦和复用。这个AnimatedBuilder就是专门复制动效管理的,并且应当努力实现复用。AnimatedBuilder的定义如下:

const AnimatedBuilder({
    Key? key,
    required Listenable animation,
    required this.builder,
    this.child,
  }) : assert(animation != null),
       assert(builder != null),
       super(key: key, listenable: animation);

其中关键的参数是builderbuilder 用于构建组件的转变动作,在 builder 里可以对要渲染的子组件进行转变操作,然后返回变换后的组件。builder 的定义如下,其中 child 实际就是 AnimatedBuilder 的 child 参数,可以根据需要是否使用。

Widget Function(BuildContext context, Widget? child)

Transform 组件介绍

在 Flutter 中,提供了一个专门用于对子组件进行转换操作的,定义如下:

const Transform({
    Key? key,
    required this.transform,
    this.origin,
    this.alignment,
    this.transformHitTests = true,
    Widget? child,
  }) : assert(transform != null),
       super(key: key, child: child);

这里的参数说明如下:

  • transform 是一个Matrix4 对象,用于定义三维空间的变换操作。
  • origin 是一个坐标偏移量,实际会加入到 Matrix4 的 translation(平移)中。
  • alignment:即转变进行的参考方位。
  • child:被转换的子组件。

我们可以通过 Transform,实现 AnimatedBuilder 的动效管理,也就是在 AnimatedBuilder 中,通过构建 Transform 对象实现动效。

应用

基本概念讲清楚了(敲黑板:很多时候大家都是直接简单看一下文档就开始用,甚至干脆复制示例代码就上,结果很可能会用得不对),可以开始撸代码了。我们来实现下面的动效。

这里其实是两个组件,通过 AnimatedBuilder 做了动效转换。在动效的一半时间是文字“点击按钮变出小姐姐”,之后的一半将组件更换为了小姐姐的图片了。使用AnimatedBuilder 的实现代码如下:

class RotationSwitchAnimatedBuilder extends StatelessWidget {
  final Widget child1, child2;
  final Animation<double> animation;
  const RotationSwitchAnimatedBuilder(
      {Key? key,
      required this.animation,
      required this.child1,
      required this.child2})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: animation,
      builder: (context, child) {
        if (animation.value < 0.5) {
          return Transform(
            transform: Matrix4.identity()
              ..rotateZ(animation.value * pi)
              ..setEntry(0, 1, -0.003),
            alignment: Alignment.center,
            child: child1,
          );
        } else {
          return Transform(
            transform: Matrix4.identity()
              ..rotateZ(pi)
              ..rotateZ(animation.value * pi)
              ..setEntry(1, 0, 0.003),
            child: child2,
            alignment: Alignment.center,
          );
        }
      },
    );
  }
}

注意第2个组件多转了180度,是未来保证停止后正好旋转360度,以免图片倒过来。另外就是这里的 child1和 child2也可以修改为使用 WidgetBuilder 函数来在需要的时候再构建组件。使用这个RotationSwitchAnimatedBuilder的组件就十分简单了,将需要操作的两个组件作为参数传过来,然后控制 Animation 对象来刷新界面就好了,对应的代码如下:

class AnimatedBuilderDemo extends StatefulWidget {
  const AnimatedBuilderDemo({Key? key}) : super(key: key);

  @override
  _AnimatedBuilderDemoState createState() => _AnimatedBuilderDemoState();
}

class _AnimatedBuilderDemoState extends State<AnimatedBuilderDemo>
    with SingleTickerProviderStateMixin {
  late Animation<double> animation;
  late AnimationController controller;

  @override
  void initState() {
    super.initState();
    controller =
        AnimationController(duration: const Duration(seconds: 1), vsync: this);
    animation = Tween<double>(begin: 0, end: 1.0).animate(controller);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('AnimatedBuilder 动画'),
      ),
      body: RotationSwitchAnimatedBuilder(
        animation: animation,
        child1: Center(
          child: Container(
            padding: EdgeInsets.all(10),
            margin: EdgeInsets.all(10),
            constraints: BoxConstraints(minWidth: double.infinity),
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(4.0),
              gradient: LinearGradient(
                colors: [
                  Colors.orange,
                  Colors.green,
                ],
              ),
            ),
            child: Text(
              '点击按钮变出小姐姐',
              style: TextStyle(
                fontSize: 20,
                color: Colors.white,
                fontWeight: FontWeight.bold,
              ),
              textAlign: TextAlign.center,
            ),
          ),
        ),
        child2: Center(
          child: Image.asset('images/beauty.jpeg'),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.play_arrow, color: Colors.white),
        onPressed: () {
          if (controller.status == AnimationStatus.completed) {
            controller.reverse();
          } else {
            controller.forward();
          }
        },
      ),
    );
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }
}

复用的话也很容易了,比如我们将一个圆形和一个矩形组件传过去,一样可以复用这个动画效果。

完整源码

总结

本篇介绍了 AnimatedBuilder 的概念和应用, Flutter 提供 AnimatedBuilder组件的核心理念是为了创建和管理可复用的动画效果。在使用的时候,应该将动画效果和组件构建分离,从而使得AnimatedBuilder构建的动画效果可以在需要的时候得到复用。

以上就是Flutter使用AnimatedBuilder实现动效复用的详细内容,更多关于Flutter动效复用的资料请关注脚本之家其它相关文章!

相关文章

  • android实现音乐播放器进度条效果

    android实现音乐播放器进度条效果

    这篇文章主要为大家详细介绍了android实现音乐播放器进度条效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-04-04
  • android中ViewPager结合Fragment进行无限滑动

    android中ViewPager结合Fragment进行无限滑动

    本篇文章中主要介绍了android中ViewPager结合Fragment进行无限滑动,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2017-03-03
  • Android开发Viewbinding委托实例详解

    Android开发Viewbinding委托实例详解

    这篇文章主要为大家介绍了Android开发Viewbinding委托实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • Android字体相关知识总结

    Android字体相关知识总结

    最近接到一个需求,大致内容是:全局替换当前项目中的默认字体,并引入 UI 设计师提供的一些新字体。于是对字体做了些研究,把自己的一些心得分享给大家。注意:本文所展示的系统源码都是基于Android-30 ,并提取核心部分进行分析
    2021-06-06
  • android9.0 默认apk权限添加方法

    android9.0 默认apk权限添加方法

    本文给大家分享android9.0 默认apk权限添加方法,默认赋予全部权限,根据包名赋予权限,通过default-permissions-google.xml的方式实现,文中通过实例代码给大家介绍的非常详细,需要的朋友参考下吧
    2021-06-06
  • Android Compose实现伸缩ToolBar的思路详解

    Android Compose实现伸缩ToolBar的思路详解

    这篇文章主要介绍了Android Compose之伸缩ToolBar的实现,本文给大家分享主要实现思路及实现过程,通过实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2021-10-10
  • Android如何自定义修改打包apk名称

    Android如何自定义修改打包apk名称

    当我们进行apk打包时,默认会生成app-debug.apk或者app-release.apk,每次都需要手动去修改apk的名称,用于区分各个版本的名称,这篇文章主要介绍了Android自定义修改打包apk名称,需要的朋友可以参考下
    2024-03-03
  • Android录音并且输出为Mp4文件的方法教程

    Android录音并且输出为Mp4文件的方法教程

    这篇文章主要给大家介绍了关于Android录音并且输出为Mp4文件的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-08-08
  • 详解Android截屏事件监听

    详解Android截屏事件监听

    本篇文章主要介绍了Android截屏事件监听,Android系统没有直接对截屏事件监听的接口,本文介绍了2种方法,有兴趣的可以了解一下。
    2016-12-12
  • Android制作简单的普通购物车

    Android制作简单的普通购物车

    这篇文章主要介绍了Android制作简单的普通购物车,利用ExpandabeListView制作购物车功能,感兴趣的小伙伴们可以参考一下
    2016-08-08

最新评论