评论

收藏

[Android] flutter 实现 有删除动画的 listview

移动开发 移动开发 发布于:2021-06-25 10:17 | 阅读数:393 | 评论:0

  个人开发app中,需要开发一个带有删除功能的ListView
  效果如下
DSC0000.gif

  需求动画分析
  列表可以滚动用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简单的改造实现的补位动画,希望留言给我地址,非常感谢

关注下面的标签,发现更多相似文章