开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 29 天,点击查看活动详情
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 }) ;
实例:
class AnimatedListRoute extends StatefulWidget {
const AnimatedListRoute({Key? key}) : super(key: key);
@override
_AnimatedListRouteState createState() => _AnimatedListRouteState();
}
class _AnimatedListRouteState extends State<AnimatedListRoute> {
var data = <String>[];
int counter = 5;
final globalKey = GlobalKey<AnimatedListState>();
@override
void initState() {
//初始化时先把数据加载出来,便于展示
for (var i = 0; i < counter; i++) {
data.add('${i + 1}');
}
super.initState();
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
AnimatedList(
key: globalKey,
initialItemCount: data.length,//具体展示的行数
itemBuilder: (
BuildContext context,
int index,
Animation<double> animation,
) {
//添加列表项时会执行渐显动画,FadeTransition动画类型,可切换为其他动画类型
return FadeTransition(
opacity: animation,
child: buildItem(context, index),//具体展示的单元行
);
},
),
buildAddBtn(),
],
);
}
// 创建一个 “+” 按钮,点击后会向列表中插入一项
Widget buildAddBtn() {
return Positioned(
child: FloatingActionButton(
child: Icon(Icons.add),//系统Icon
onPressed: () {
// 添加一个列表项;注意一定要先把数据添加到UI的数据源中
data.add('${++counter}');
// 告诉列表项有新添加的列表项
globalKey.currentState!.insertItem(data.length - 1);
print('添加 $counter');
},
),
bottom: 30,
left: 0,
right: 0,
);
}
// 构建列表项
Widget buildItem(context, index) {
String char = data[index];
return ListTile(
//数字不会重复,所以作为Key
key: ValueKey(char),
title: Text(char),
trailing: IconButton(
icon: Icon(Icons.delete),
// 点击时删除
onPressed: () => onDelete(context, index),
),
);
}
void onDelete(context, index) {
//删除动画
setState(() {
globalKey.currentState!.removeItem(
index,
(context, animation) {
// 删除过程执行的是反向动画,animation.value 会从1变为0
var item = buildItem(context, index);
print('删除 ${data[index]}');
data.removeAt(index);
// 删除动画是一个合成动画:渐隐 + 缩小列表项告诉
return FadeTransition(//动画类型渐隐
opacity: CurvedAnimation(//指定具体的动画样式
parent: animation,
//让透明度变化的更快一些
curve: const Interval(0.5, 1.0),//动画时间比例
),
// 不断缩小列表项的高度
child: SizeTransition(//尺寸变化动画:缩小动画
sizeFactor: animation,
axisAlignment: 0.0,//缩小至那个位置
child: item,//具体的item
),
);
},
duration: Duration(milliseconds: 200), // 动画时间为 200 ms
);
});
}
}
注意:数据是单独维护,调用AnimatedListState的插入和移除方法只是相当于一个通知:什么位置执行插入或删除动画,具体的展示仍然是数据驱动。