Flutter AnimatedList 实现动态列表

发布于 1周前 作者 phonegap100 最后一次编辑是 5天前 来自 分享

Flutter AnimatedList 实现动态列表视频教程https://www.bilibili.com/video/BV1S4411E7LY?p=46

一、 AnimatedList实现动画

AnimatedList 和 ListView 的功能大体相似,不同的是, AnimatedList 可以在列表中插入或删除节点时执行一个动画,在需要添加或删除列表项的场景中会提高用户体验。

AnimatedList 是一个 StatefulWidget,它对应的 State 类型为 AnimatedListState,添加和删除元素的方法位于 AnimatedListState 中:

void insertItem(int index, { Duration duration = _kDuration });

void removeItem(int index, AnimatedListRemovedItemBuilder builder, { Duration duration = _kDuration }) ;

AnimatedList常见属性:

属性 描述
key globalKey final globalKey = GlobalKey<AnimatedListState>();
initialItemCount 子元素数量
itemBuilder 方法 ( BuildContext context, int index, Animation<double> animation) {}

关于GlobalKey: 每个Widget都对应一个Element,我们可以直接对Widget进行操作,但是无法直接操作Widget对应的Element。而GlobalKey就是那把直接访问Element的钥匙。通过GlobalKey可以获取到Widget对应的Element

二、 AnimatedList增加列表FadeTransition、ScaleTransition

FadeTransition Demo

import 'package:flutter/material.dart';

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

  @override
  State<AnimatedListPage> createState() => _AnimatedListPageState();
}

class _AnimatedListPageState extends State<AnimatedListPage> {
 
  final globalKey = GlobalKey<AnimatedListState>();
   List<String> list = ["第一条数据","第二条数据"];
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: (){
          list.add("这是一个数据");
          globalKey.currentState!.insertItem(list.length - 1);
        },
        child: const Icon(Icons.add),
      ),
      appBar: AppBar(
        title: const Text("AppBar组件"),
      ),
      body: AnimatedList(
          key: globalKey,
          initialItemCount: list.length,
          itemBuilder: (context, index, animation) {
            return FadeTransition(
              opacity: animation,
              child: ListTile(
                title: Text(list[index]),
                trailing: Icon(Icons.delete)
              ),
            );
          }),
    );
  }
}

ScaleTransition demo

import 'package:flutter/material.dart';

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

  @override
  State<AnimatedListPage> createState() => _AnimatedListPageState();
}

class _AnimatedListPageState extends State<AnimatedListPage> {
 
  final globalKey = GlobalKey<AnimatedListState>();
   List<String> list = ["第一条数据","第二条数据"];
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: (){
          list.add("这是一个数据");
          globalKey.currentState!.insertItem(list.length - 1);
        },
        child: const Icon(Icons.add),
      ),
      appBar: AppBar(
        title: const Text("AppBar组件"),
      ),
      body: AnimatedList(
          key: globalKey,
          initialItemCount: list.length,
          itemBuilder: (context, index, animation) {
            print(animation);
            return ScaleTransition(             
              scale: animation,
              child: ListTile(
                title: Text(list[index]),
                trailing: Icon(Icons.delete)
              ),
            );
          }),
    );
  }
}

三、 AnimatedList 删除列表

import 'dart:async';

import 'package:flutter/material.dart';

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

  @override
  State<AnimatedListPage> createState() => _AnimatedListPageState();
}

class _AnimatedListPageState extends State<AnimatedListPage> {
  final globalKey = GlobalKey<AnimatedListState>();
  bool flag = true;
  List<String> list = ["第一条数据", "第二条数据"];
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
  }

  Widget _buildItem(context, index) {
    return ListTile(
        key: ValueKey(index),
        title: Text(list[index]),
        trailing: IconButton(
          icon: Icon(Icons.delete),
          // 点击时删除
          onPressed: () => _deleteItem(context, index),
        ));
  }

  _deleteItem(context, index) {
    if (flag == true) {
      flag = false;
      print(index);
      //注意:删除后需要重新setState
      setState(() {
        //  删除过程执行的是反向动画,animation.value 会从1变为0
        globalKey.currentState!.removeItem(index, (context, animation) {
          //注意先build然后再去删除
          var item = _buildItem(context, index);
          list.removeAt(index);             
          return FadeTransition(
            opacity: animation,
            child: item,
          );
        },duration: Duration(milliseconds: 500));
      });
      //解决快速删除bug  重置flag
      const timeout = Duration(milliseconds: 600);
      Timer.periodic(timeout, (timer) { 
        flag=true;
        timer.cancel();
      });
     
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // 增加 animation.value 会从0变为1
          list.add("这是一个数据");
          globalKey.currentState!.insertItem(list.length - 1);
        },
        child: const Icon(Icons.add),
      ),
      appBar: AppBar(
        title: const Text("AppBar组件"),
      ),
      body: AnimatedList(
          key: globalKey,
          initialItemCount: list.length,
          itemBuilder: (context, index, animation) {
            return FadeTransition(
              opacity: animation,
              child: _buildItem(context, index),
            );
          }),
    );
  }
}

回到顶部