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 }) ;
下面咱们看一个示例:完成下面这样的一个列表,点击底部 + 按钮时向列表追加一个列表项;点击每个列表项后边的删去按钮时,删去该列表项,增加和删去时分别履行指定的动画。
初始的时分有5个列表项,先点击了 + 号按钮,会增加一个 6,增加进程履行渐显动画。然后点击了 4 后边的删去按钮,删去的时分履行了一个渐隐+缩短的合成动画。
下面是完成代码:
import 'package:demo202112/utils/common_appbar.dart';
import 'package:flutter/material.dart';
import 'dart:math';
/// @Author wywinstonwy
/// @Date 2022/1/20 8:42 上午
/// @Description:
class MyAnimatedList extends StatefulWidget {
const MyAnimatedList({Key? key}) : super(key: key);
@override
_MyAnimatedListState createState() => _MyAnimatedListState();
}
class _MyAnimatedListState extends State<MyAnimatedList> {
var data = <ItemModel>[];
int counter = 5;
final globalKey = GlobalKey<AnimatedListState>();
@override
void initState() {
for (var i = 0; i < counter; i++) {
Color color = Color.fromRGBO(Random().nextInt(256), Random().nextInt(256),
Random().nextInt(256), 1);
String title = '${i + 1}';
ItemModel item = ItemModel(backColor: color, title: title);
data.add(item);
}
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: getAppBar('AnimatedList'),
body: Stack(
children: [_buildAnimatedList(), buildAddBtn()],
),
);
}
buildAddBtn() {
return Positioned(
child: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
//增加一个列表项目
// data.add(('${++counter}'));
Color color = Color.fromRGBO(Random().nextInt(256),
Random().nextInt(256), Random().nextInt(256), 1);
String title = '${++counter}';
ItemModel item = ItemModel(backColor: color, title: title);
data.add(item);
// 告诉列表项有新增加的列表项
globalKey.currentState!.insertItem(data.length - 1);
print('增加 $counter');
},
),
bottom: 30,
left: 0,
right: 0,
);
}
_buildAnimatedList() {
return AnimatedList(
key: globalKey,
initialItemCount: data.length,
itemBuilder: (context, index, Animation<double> animation) {
return FadeTransition(
opacity: animation,
child: _buildItem(context, index),
);
});
}
_buildItem(context, index) {
ItemModel itemModel = data[index];
return Container(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 10),
margin: const EdgeInsets.only(bottom: 10),
color: itemModel.backColor,
key: ValueKey(itemModel.title),
child: Row(
children: [
Container(
margin: const EdgeInsets.only(left: 10),
child: Text(
itemModel.title,
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
),
Expanded(child: Container()),
IconButton(
onPressed: () {
onDelete(context, index);
},
icon: const Icon(
Icons.delete,
color: Colors.red,
size: 30,
)),
],
),
);
}
onDelete(context, index) {
//
globalKey.currentState!.removeItem(index, (context, animation) {
// 删去进程履行的是反向动画,animation.value 会从1变为0
var item = _buildItem(context, 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,
),
);
}, duration: const Duration(milliseconds: 200) //动画时间200毫秒
);
}
}
class ItemModel extends StatelessWidget {
const ItemModel({Key? key, required this.backColor, required this.title})
: super(key: key);
final Color backColor;
final String title;
@override
Widget build(BuildContext context) {
return Container();
}
}
运转效果:
删去的时分需求咱们经过AnimatedListState 的 removeItem 方法来使用删去动画。
代码很简单,但咱们需求留意,咱们的数据是单独在 data 中保护的,调用 AnimatedListState 的刺进和移除方法知识相当于一个通知:在什么位置履行刺进或移除动画,仍然是数据驱动的(响应式并非命令式)。
官方文档:api.flutter-io.cn/flutter/wid…
同时需求关注SliverAnimatedList,用法和AnimatedList相同。
SliverAnimatedList, a sliver that animates items when they are inserted or removed from a list.
demo示例地址:gitee.com/wywinstonwy…