上山打老虎 发表于 2021-6-25 10:17:25

flutter 实现 有删除动画的 listview

  个人开发app中,需要开发一个带有删除功能的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简单的改造实现的补位动画,希望留言给我地址,非常感谢

页: [1]
查看完整版本: flutter 实现 有删除动画的 listview