小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
平时开发项目时,经常会有列表listview删除刷新的需求,如果直接移除数据然后刷新列表没有任何动画的话会显得很生硬,用户仿佛无感知一样。那么这个时候加入删除动画就非常有必要了,有很多人可能会考虑用到AnimatedList
组件,但是个人感觉用起来比较复杂一点,这里从其他角度介绍下一种实现方式。
先看一下效果:
实现
实现上其实很简单,思路是将Listview的item外层使用AnimatedOpacity
渐变动画组件嵌套,指定动画时长,opacity属性则根据item对应的数据是否被移除的标志位设置为0或1。当点击移除时,首先设置itemBean的removeFlg置为true,这时setState
就会触发对应item的渐变动画,但是这里需要注意的是即使item动画变为0时,列表的item其实也没有被真正移除,所以需要在AnimatedOpacity
所设置的动画时长延迟后,做一个真正移除数据的操作,这样列表就看起来是一个衔接非常好的动画渐变移除效果。
代码如下:
import 'package:flutter/material.dart';
class AnimatedListPage extends StatefulWidget {
const AnimatedListPage({Key key}) : super(key: key);
@override
_AnimatedListPageState createState() => _AnimatedListPageState();
}
class _AnimatedListPageState extends State<AnimatedListPage> {
List<DemoBean> _list = [];
@override
void initState() {
// TODO: implement initState
super.initState();
_list..add(DemoBean(false,"安顺达斯柯达卡"))
..add(DemoBean(false,"爱神的箭卡仕达看见爱上对话框"))
..add(DemoBean(false,"as建档立卡手机打开拉四季豆"))
..add(DemoBean(false,"请问凸起物恶徒区位图全网通也士"))
..add(DemoBean(false,"在你先别在VX你BZVX你"));
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(
child: ListView.separated(
itemCount: _list.length,
itemBuilder: (ctx,index){
return AnimatedOpacity(
duration: const Duration(milliseconds: 500),
// height: _list[index].remove ? 0 : 100,
opacity: _list[index].remove ? 0 : 1,
child: Container(
height: 100,
color: Colors.blue,
alignment: Alignment.center,
child: Text("${_list[index].text}")),
);
},separatorBuilder: (ctx,index){
return Divider(height: 1,);
},),
),
GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: (){
setState(() {
_list[1].remove = true;
});
Future.delayed(Duration(milliseconds: 500),(){
setState(() {
_list.removeAt(1);
});
});
},
child: Container(
height: 50,
alignment: Alignment.center,
child: Text("移除一个"),
),
)
],
),
);
}
}
class DemoBean{
bool remove;
String text;
DemoBean(this.remove, this.text);
}
关键点
关键点就在于首先设置item对应数据的移除标志位为true,然后再延时AnimatedOpacity组件的对应时长后真正的移除数据并刷新,时长是可以根据自己的体验效果进行调试更改。
setState(() {
_list[1].remove = true;
});
Future.delayed(Duration(milliseconds: 500),(){
setState(() {
_list.removeAt(1);
});
});
拓展
看到这有人可能也会想到,既然可以使用AnimatedOpacity组件完成移除动画,那么使用AnimatedContainer
组件是不是也可以实现移除的效果?没错,其实Animated系列的组件其实都可以使用。下面是AnimatedContainer
的例子:
可以看上去效果不如使用AnimatedOpacity,除此之外其实还有很多组件可以使用,总之为一个列表添加移除动画还是很有必要的~