flutter 实现 有删除动画的 listview

个人开发app中,需要开发一个带有删除功能的ListView

效果如下

flutter 实现 有删除动画的 listview

 

 

需求动画分析

 

列表可以滚动用listView,

有两个动画,第一个动画是透明度变化,第二个是size变化

是顺序执行

 

实现过程

新建一个动画页面进行单独控制

记得用statefulwidget类,这第二个动画之间涉及到页面刷新切换widget

记得with tickerproviderstatemixin 这个是动画类状态管理的必备

class AnimationListItem extends StatefulWidget {   AnimationListItem();   @override   _AnimationListItemState createState() => _AnimationListItemState(); }
class _AnimationListItemState extends State<AnimationListItem>     with TickerProviderStateMixin {   @override   Widget build(BuildContext context) {     // TODO: implement build     return Container();   } }

 

动画流程

声明

//控制器   AnimationController lucencyController;   AnimationController sizeController; // 动画
  Animation<double> lucencyAnimation;   Animation<double> sizeAnimation;

 

初始化

///必须在initstate这个生命周期进行初始化   @override   void initState() {     // TODO: implement initState     super.initState();     lucencyController =         AnimationController(vsync: this, duration: Duration(milliseconds: 150));     lucencyAnimation = Tween(begin: 1.0, end: 0.0).animate(         CurvedAnimation(parent: lucencyController, curve: Curves.easeOut));
    sizeController =         AnimationController(vsync: this, duration: Duration(milliseconds: 250));     sizeAnimation = Tween(begin: 1.0, end: 0.0).animate(         CurvedAnimation(parent: sizeController, curve: Curves.easeOut));   }

 

注销 

@override   void dispose() {     lucencyController.dispose();     sizeController.dispose();     super.dispose();   }

 

最后内容呈现

class AnimationListItem extends StatefulWidget {   AnimationListItem();   @override   _AnimationListItemState createState() => _AnimationListItemState(); }
class _AnimationListItemState extends State<AnimationListItem>     with TickerProviderStateMixin {   AnimationController lucencyController;   AnimationController sizeController;
  Animation<double> lucencyAnimation;   Animation<double> sizeAnimation;
  bool isChange = false;
  @override   void initState() {     // TODO: implement initState     super.initState();     lucencyController =         AnimationController(vsync: this, duration: Duration(milliseconds: 150));     lucencyAnimation = Tween(begin: 1.0, end: 0.0).animate(         CurvedAnimation(parent: lucencyController, curve: Curves.easeOut));
    sizeController =         AnimationController(vsync: this, duration: Duration(milliseconds: 250));     sizeAnimation = Tween(begin: 1.0, end: 0.0).animate(         CurvedAnimation(parent: sizeController, curve: Curves.easeOut));   }
  @override   Widget build(BuildContext context) {     return buildItemBox();   }
  @override   void dispose() {     lucencyController.dispose();     sizeController.dispose();     super.dispose();   }
  Widget buildItemBox() {     return isChange         ? SizeTransition(             axis: Axis.vertical,             sizeFactor: sizeAnimation,             child: Container(               height: duSetWidth(100),               width: double.infinity,             ),           )         : FadeTransition(             opacity: lucencyAnimation,             child: Container(               alignment: Alignment.center,               padding: EdgeInsets.only(                 left: duSetWidth(15),                 right: duSetWidth(15),               ),               height: duSetWidth(100),               child: buildRow(),             ),           );   }
  Widget buildRow() {     ///设置显示的样式     bool _isSub = false;     Color _isSubColor = Color.fromRGBO(245, 77, 130, 1);     Color _isSubBackColor = Colors.transparent;
    Widget isSubWidget = InkWell(       child: Container(         alignment: Alignment.center,         width: duSetWidth(55),         height: duSetWidth(28),         decoration: BoxDecoration(           color: _isSubBackColor,           border: Border.all(color: _isSubColor),           borderRadius: BorderRadius.circular(duSetWidth(15)),         ),         child: Text(           '+ 书架',           style: TextStyle(             color: _isSubColor,           ),         ),       ),       onTap: () {         if (_isSub)           print('dasd');         else           print('dsada');       },     );
    return Row(       mainAxisAlignment: MainAxisAlignment.spaceBetween,       children: [         Container(           width: duSetWidth(60),           height: duSetWidth(80),           child: ClipRRect(             borderRadius: BorderRadius.circular(duSetWidth(5)),             child: Image.network(               'https://gimg2.baidu.com/image_search/src=http%3A%2F%2F00.minipic.eastday.com%2F20170307%2F20170307164725_114ea3c04f605e59bd10699f37870267_13.jpeg&refer=http%3A%2F%2F00.minipic.eastday.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1623596389&t=946dba98698d8d67d773ea8f7af55f45',               fit: BoxFit.cover,             ),           ),         ),         Container(           width: duSetWidth(155),           height: duSetWidth(80),           child: Column(             mainAxisAlignment: MainAxisAlignment.center,             children: [               Container(                 height: duSetWidth(25),                 alignment: Alignment.centerLeft,                 width: double.infinity,                 child: Text(                   '这是标题',                   maxLines: 1,                   overflow: TextOverflow.ellipsis,                   style: TextStyle(                     color: Colors.white,                     fontSize: duSetFontSize(16),                   ),                 ),               ),               Container(                 height: duSetWidth(20),                 alignment: Alignment.centerLeft,                 width: double.infinity,                 child: Text(                   '这是副标题',                   maxLines: 1,                   overflow: TextOverflow.ellipsis,                   style: TextStyle(                     color: Color.fromRGBO(162, 168, 186, 1),                     fontSize: duSetFontSize(14),                   ),                 ),               ),             ],           ),         ),         Container(           width: duSetWidth(100),           height: duSetWidth(80),           padding: EdgeInsets.only(             top: duSetWidth(4),           ),           alignment: Alignment.center,           child: Row(             mainAxisAlignment: MainAxisAlignment.spaceBetween,             children: [               isSubWidget,               InkWell(                 onTap: () async {                   await lucencyController.forward();                   setState(() {                     isChange = true;                     sizeController.forward();                   });                 },                 child: Container(                   alignment: Alignment.center,                   width: duSetWidth(35),                   height: duSetWidth(28),                   decoration: BoxDecoration(                     border: Border.all(                       color: Color.fromRGBO(113, 118, 140, 1),                     ),                     borderRadius: BorderRadius.circular(duSetWidth(15)),                   ),                   child: Icon(                     Icons.delete,                     color: Color.fromRGBO(113, 118, 140, 1),                     size: duSetFontSize(16),                   ),                 ),               ),             ],           ),         )       ],     );   } }

dusetwidth是我自定义的函数可以不用管,自己替换

 

下列是在页面使用

class HistoryPage extends StatefulWidget {   @override   _HistoryPageState createState() => _HistoryPageState(); }
class _HistoryPageState extends State<HistoryPage> {    @override   Widget build(BuildContext context) {     return Scaffold(       appBar: AppBar(),       body: ListView(         children: [           AnimationListItem(),           AnimationListItem(),           AnimationListItem(),           AnimationListItem(),         ],       ),     );   }
  /// 构造appbar   Widget buildAppabr() {     return AppBar(       backgroundColor: Color.fromRGBO(33, 39, 46, 1),       brightness: Brightness.dark,       centerTitle: true,       title: Text(         '浏览记录',         style: TextStyle(           fontSize: duSetFontSize(16),           color: Colors.white,         ),       ),       leading: IconButton(         icon: Icon(           Icons.arrow_back_ios,           color: Colors.white,           size: duSetFontSize(18),         ),         onPressed: () {           Get.back();         },       ),     );   } }

这个我原来是准备使用animatedList来进行实现的,最后发现,animatedList里面只能设置移除动画,不能实现补位动画

第一个透明度的动画就是移除动画,第二个size变化就是补位动画,

animatedList没有补位,所以下方list直接移动上去会显得非常突兀,我看了看源码,修改较为麻烦。所以就直接用动画变换来写

这个List内的内容,并不是直接移除,而是替换成高低为0 的一个盒子

如果有animatedList简单的改造实现的补位动画,希望留言给我地址,非常感谢

 
上一篇:ListView详解0


下一篇:腾讯团队实力打造flutter入门教程,全网独家首发!