Flutter开发·快把这个Listview item移除动画加到你的项目里

1,114 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

平时开发项目时,经常会有列表listview删除刷新的需求,如果直接移除数据然后刷新列表没有任何动画的话会显得很生硬,用户仿佛无感知一样。那么这个时候加入删除动画就非常有必要了,有很多人可能会考虑用到AnimatedList组件,但是个人感觉用起来比较复杂一点,这里从其他角度介绍下一种实现方式。

先看一下效果:

2021-10-30 16.36.05.gif

实现

实现上其实很简单,思路是将Listview的item外层使用AnimatedOpacity渐变动画组件嵌套,指定动画时长,opacity属性则根据item对应的数据是否被移除的标志位设置为0或1。当点击移除时,首先设置itemBean的removeFlg置为true,这时setState就会触发对应item的渐变动画,但是这里需要注意的是即使item动画变为0时,列表的item其实也没有被真正移除,所以需要在AnimatedOpacity所设置的动画时长延迟后,做一个真正移除数据的操作,这样列表就看起来是一个衔接非常好的动画渐变移除效果。

代码如下:

import 'package:flutter/material.dart';

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

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

class _AnimatedListPageState extends State<AnimatedListPage> {

  List<DemoBean> _list = [];

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _list..add(DemoBean(false,"安顺达斯柯达卡"))
      ..add(DemoBean(false,"爱神的箭卡仕达看见爱上对话框"))
      ..add(DemoBean(false,"as建档立卡手机打开拉四季豆"))
      ..add(DemoBean(false,"请问凸起物恶徒区位图全网通也士"))
      ..add(DemoBean(false,"在你先别在VX你BZVX你"));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          Expanded(
            child: ListView.separated(
                itemCount: _list.length,
                itemBuilder: (ctx,index){
              return AnimatedOpacity(
                duration: const Duration(milliseconds: 500),
                // height: _list[index].remove ? 0 : 100,
                opacity: _list[index].remove ? 0 : 1,
                child: Container(
                    height: 100,
                    color: Colors.blue,
                    alignment: Alignment.center,
                    child: Text("${_list[index].text}")),
              );
            },separatorBuilder: (ctx,index){
               return Divider(height: 1,);
            },),
          ),
          GestureDetector(
            behavior: HitTestBehavior.translucent,
            onTap: (){
              setState(() {
                _list[1].remove = true;
              });
              Future.delayed(Duration(milliseconds: 500),(){
                setState(() {
                  _list.removeAt(1);
                });
              });
            },
            child: Container(
              height: 50,
              alignment: Alignment.center,
              child: Text("移除一个"),
            ),
          )
        ],
      ),
    );
  }
}

class DemoBean{

  bool remove;
  String text;

  DemoBean(this.remove, this.text);

}

关键点

关键点就在于首先设置item对应数据的移除标志位为true,然后再延时AnimatedOpacity组件的对应时长后真正的移除数据并刷新,时长是可以根据自己的体验效果进行调试更改。

setState(() {
  _list[1].remove = true;
});
Future.delayed(Duration(milliseconds: 500),(){
  setState(() {
    _list.removeAt(1);
  });
});

拓展

看到这有人可能也会想到,既然可以使用AnimatedOpacity组件完成移除动画,那么使用AnimatedContainer组件是不是也可以实现移除的效果?没错,其实Animated系列的组件其实都可以使用。下面是AnimatedContainer的例子:

2021-10-30 16.52.14.gif

可以看上去效果不如使用AnimatedOpacity,除此之外其实还有很多组件可以使用,总之为一个列表添加移除动画还是很有必要的~