banner
MiniKano

MiniKano

This is MiniKano's blog based on Blockchain technology. 新手,请多关照~
github

使用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);
        },
      ),
    );
  }
}

效果圖#

1-3[1].gif

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。