LOADING

Flutter 使用AnimatedList实现列表项目增加和删除

AnimatedList是一个有状态的Widget,对应的State类型为AnimatedListState

AnimatedList的结构如下:

const AnimatedList({
  Key? key,
  required Widget Function(BuildContext, int, Animation<double>) itemBuilder,//数据构造器
  int initialItemCount = 0,//初始化的数据的总长度
  Axis scrollDirection = Axis.vertical,//滚动方向
  bool reverse = false,//是否从下往上显示
  ScrollController? controller,//滚动的controller,非必填,控制列表的滚动位置
  bool? primary,//是否关联父级滚动
  ScrollPhysics? physics,//如何响应用户操作
  bool shrinkWrap = false,
  EdgeInsetsGeometry? padding,//内边距
  Clip clipBehavior = Clip.hardEdge,
})

State里有两个方法可以添加和删除列表里的元素:

注意,如果List绑定了数据源List的话,不能直接通过remove或者add元素达到更新列表的效果,还需要执行下面的方法:

//插入元素
void insertItem(
    int index, 
    {Duration duration = _kDuration}
)
//删除元素
void removeItem(
  int index,
  Widget Function(BuildContext, Animation<double>) builder, {
  Duration duration = _kDuration,
})

添加和删除的时候都会显示指定的动画

使用insertItem、removeItem时通常需要配合globalKey,但globalKey需要指定泛型,这样才能调用到增加和删除列表元素的方法:

final globalKey = GlobalKey<AnimatedListState>();

添加元素的时候只需要:

list.add("新增数据");
globalKey.currentState!.insertItem(list.length - 1);

删除元素的时候比较麻烦,因为需要显示元素离开时候的动画然后再删除对应数据源的条目:

一般我们需要建一个_buildItem方法来动态创建子元素,执行removeItem的时候先在回调里面创建一个一摸一样的子元素,如何使用动画淡出,最后删除数据数组中的数据即可.

//删除元素
_delItem(index) {
    globalKey.currentState!.removeItem(index, (context, animation) {
        //获取要删除的元素,让他淡出显示
        var removeItem = _buildItem(index);
        return FadeTransition(
            //执行动画
            opacity: animation,
            child: removeItem,
        );
    });
    list.removeAt(index); //删除数组中的数据
}

完整代码

//AnimatedList
class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  //定义一个globalKey
  final globalKey = GlobalKey<AnimatedListState>();
  List<String> list = ["第一条数据", "第二条数据"];
  bool flag = true;
  Widget _buildItem(index) {
    return ListTile(
      title: Text(list[index]),
      trailing: IconButton(
        icon: const Icon(Icons.delete),
        onPressed: () {
          //执行删除
          _delItem(index);
        },
      ),
    );
  }

//删除元素
  _delItem(index) {
    globalKey.currentState!.removeItem(index, (context, animation) {
      //获取要删除的元素,让他淡出显示
      var removeItem = _buildItem(index);
      list.removeAt(index); //删除数组中的数据
      return FadeTransition(
        //执行动画
        opacity: animation,
        child: removeItem,
      );
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("kano")),
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.add),
        //这样直接操作list不会对AnimatedList生效
        onPressed: () {
          // setState(() {
          //   list.add("新增数据");
          // });
          ///使用AnimatedList中的insertItem方法
          list.add("新增数据");
          globalKey.currentState!.insertItem(list.length - 1);
        },
      ),
      //带有动画的List列表
      body: AnimatedList(
        key: globalKey,
        initialItemCount: list.length,
        itemBuilder: (context, index, animation) {
          //fade过渡 opacity 进入从0到1 离开则相反
          return FadeTransition(opacity: animation);
          //scale过渡
          // return ScaleTransition(scale: animation);
        },
      ),
    );
  }
}

效果图

    发表回复

    电子邮件地址不会被公开。必填项已用 * 标注