flutter AnimatedSwitcher 动画切换过渡组件 跑马灯动画封装


前言

本篇文章将记录 AnimatedSwitcher 过渡组件,这个组件动画是一个新的小部件来代替另一个。它提供了一个很好的过渡,使应用程序非常流畅。始终为其子小部件添加一个键以确保其正常工作。


一、AnimatedSwitcher 简介

AnimatedSwitcher 可以同时对其新、旧子元素添加显示、隐藏动画。也就是说在AnimatedSwitcher的子元素发生变化时,会对其旧元素和新元素做动画,我们先看看AnimatedSwitcher 的源码:

const AnimatedSwitcher({
    
    
  Key? key,
  this.child,
  required this.duration, // 新child显示动画时长
  this.reverseDuration,// 旧child隐藏的动画时长
  this.switchInCurve = Curves.linear, // 新child显示的动画曲线
  this.switchOutCurve = Curves.linear,// 旧child隐藏的动画曲线
  this.transitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, // 动画构建器
  this.layoutBuilder = AnimatedSwitcher.defaultLayoutBuilder, //布局构建器
})

当AnimatedSwitcher的 child 发生变化时(类型或 Key 不同),旧 child 会执行隐藏动画,新 child 会执行执行显示动画。究竟执行何种动画效果则由transitionBuilder参数决定,该参数接受一个AnimatedSwitcherTransitionBuilder类型的 builder,定义如下:

typedef AnimatedSwitcherTransitionBuilder =
  Widget Function(Widget child, Animation<double> animation);

关于AnimatedSwitcher 组件的介绍就到这里,具体的属性的使用,有兴趣的可以去私下尝试一下,下面我们先来一个简单的使用。

二、AnimatedSwitcher 的简单使用

我们先来实现一个计数器,然后在每一次自增的过程中,旧数字执行缩小动画隐藏,新数字执行放大动画显示,代码如下

 AnimatedSwitcher(
              duration: Duration(milliseconds: 1000), // 新child 显示时长
              reverseDuration: Duration(milliseconds: 500), // 旧child 显示时长
              // transitionBuilder 动画展示的样式,日常开发中,可以根据实际需要,来设置不同的样式
              transitionBuilder: (Widget child, Animation<double> animation){
    
    
                return ScaleTransition(scale: animation, child: child,);
              },
              child: Text(
                "${
      
      count}",
                // 显示指定key, 不同的key 会被认为是不同的text,不添加key,不会执行动画
                key: ValueKey(count),
                style: TextStyle(
                  color: Colors.blue,
                  fontSize: 32
                ),
              ),
            ),
            MaterialButton(
              onPressed: () {
    
    
                setState(() {
    
    
                  count += 1;
                });
              },
              child: Text("count+1"),
            ),

运行上面的代码,当你点击+1 的时候,数字会有一个旧数字缩小,新数字放大的一个展示

在这里插入图片描述

三、AnimatedSwitcher 自定义跑马灯动画

如果项目需求,需要我们的数据从右侧进来,左侧出去,那么我们现在就没法去实现了,如果需要实现,就需要我们去改造一下SlideTransition 组件,下面一起来看改造代码

class CustomSlideTransitionWidget extends AnimatedWidget {
    
    
  final Widget child;
  final bool transformHitTests;

  const CustomSlideTransitionWidget({
    
    
    Key? key,
    required Animation<Offset> position,
    required this.child,
    this.transformHitTests = true,
  }) : super(key: key, listenable: position);

  
  Widget build(BuildContext context) {
    
    
    final position = listenable as Animation<Offset>;
    Offset offset = position.value;
    if (position.status == AnimationStatus.reverse) {
    
    
      offset = Offset(-offset.dx, offset.dy);
    }

    return FractionalTranslation(
      translation: offset,
      transformHitTests: transformHitTests,
      child: child,
    );
  }
}

上面代码中,与SlideTransition唯一的不同就是对动画的反向执行进行了定制(从左边滑出隐藏),position.status == AnimationStatus.reverse

接下来我们来使用验证

AnimatedSwitcher(
              duration: Duration(milliseconds: 1000), // 新child 显示时长
              reverseDuration: Duration(milliseconds: 500), // 旧child 显示时长
              transitionBuilder: (Widget child, Animation<double> animation) {
    
    
                var tween =
                    Tween<Offset>(begin: Offset(1, 0), end: Offset(0, 0));
                return CustomSlideTransitionWidget(
                    position: tween.animate(animation), child: child);
              },
              child: Text(
                "${
      
      count}",
                // 显示指定key, 不同的key 会被认为是不同的text,不添加key,不会执行动画
                key: ValueKey(count),
                style: TextStyle(color: Colors.blue, fontSize: 32),
              ),
            ),

运行结果输出:

在这里插入图片描述

当我们点击+1 的时候,新的数字会从右侧出来,旧的数字会从左侧消失。

四、SlideTransitionX 的封装

其实本篇文章,到这里就已经写完了,但是如果我们需要实现“左入右出”、“上入下出”或者 “下入上出”怎么办?这样是不是每一种模式,都得去定义一个Transition,这样无形中会很麻烦,那么接下来,我们就来继续改造一下CustomSlideTransitionWidget 组件,把上面说的都封装进去

class CustomSlideTransitionWidget extends AnimatedWidget {
    
    
  final Widget child;
  final bool transformHitTests;
  final AxisDirection direction;
  late Tween<Offset> _tween;

  CustomSlideTransitionWidget({
    
    
    Key? key,
    required Animation<double> position,
    required this.child,
    this.transformHitTests = true,
    this.direction = AxisDirection.down,
  }) : super(key: key, listenable: position) {
    
    
    switch (direction) {
    
    
      case AxisDirection.up:
        _tween = Tween(begin: const Offset(0, 1), end: const Offset(0, 0));
        break;
      case AxisDirection.right:
        _tween = Tween(begin: const Offset(-1, 0), end: const Offset(0, 0));

        break;
      case AxisDirection.down:
        _tween = Tween(begin: const Offset(0, -1), end: const Offset(0, 0));

        break;
      case AxisDirection.left:
        _tween = Tween(begin: const Offset(1, 0), end: const Offset(0, 0));

        break;
    }
  }

  
  Widget build(BuildContext context) {
    
    
    final position = listenable as Animation<double>;
    Offset offset = _tween.evaluate(position);

    if (position.status == AnimationStatus.reverse) {
    
    
      switch (direction) {
    
    
        case AxisDirection.up:
          offset = Offset(offset.dx, -offset.dy);
          break;
        case AxisDirection.right:
          offset = Offset(-offset.dx, offset.dy);
          break;
        case AxisDirection.down:
          offset = Offset(offset.dx, -offset.dy);
          break;
        case AxisDirection.left:
          offset = Offset(-offset.dx, offset.dy);
          break;
      }
    }

    return FractionalTranslation(
      translation: offset,
      transformHitTests: transformHitTests,
      child: child,
    );
  }
}

使用方法

AnimatedSwitcher(
              duration: Duration(milliseconds: 1000), // 新child 显示时长
              reverseDuration: Duration(milliseconds: 500), // 旧child 显示时长
              transitionBuilder: (Widget child, Animation<double> animation) {
    
    
                return CustomSlideTransitionWidget(
                  position: animation,
                  // 上入下出
                  direction: AxisDirection.down,
                  child: child,
                );
              },
              child: Text(
                "${
      
      count}",
                // 显示指定key, 不同的key 会被认为是不同的text,不添加key,不会执行动画
                key: ValueKey(count),
                style: TextStyle(color: Colors.blue, fontSize: 32),
              ),
            ),

在使用的时候,我们只需要选择一个direction 就可以了

运行效果如下:
请添加图片描述


总结

本篇文章不仅记录了AnimatedSwitcher的详细用法,同时也介绍了打破AnimatedSwitcher动画对称性的方法。然后经过我们自己的封装改造,AnimatedSwitcher 在日常开发过程中,将十分的受用。

猜你喜欢

转载自blog.csdn.net/u010755471/article/details/127978765
今日推荐