Flutter实现自定义二级列表

在Flutter开发中,其实系统已经给我们提供了一个可靠的二级列表展开的API(ExpansionPanelList),我们先看系统的二级列表展开效果,一次只能展开一个,用ExpansionPanelList.radio实现

gif.gif

由此可见,已经能很大部分满足我们的需求了,

但是…在使用过程中,我发现无法改变右侧icon的位置,或者是想隐藏icon,只能改其颜色

expandIconColor: Colors.white,

但是,这个时候cell的点击事件只有下图中黄色区域

image.png

如果想让整个cell都能被点击,只能设置

canTapOnHeader: true,

但是,如果设置了这个属性,改变icon颜色的这个expandIconColor就失效了,所有在使用过程中,不能很好的耦合自身项目需求,而我们的项目,是要让icon紧挨着在text的后面,如下图

image.png

查阅了很多资料,如果使用系统提供的API,不能实现项目中想要的效果,无奈只能自己造轮子了,实现效果如下

gif.gif

使用自定义的,自己想怎么布局就怎么布局,没那么多耦合性,下面直接贴出代码,文章末尾会贴出系统和自定义两种方法分别实现的demo

先开系统实现、代码里面都标准了注释,这里就不一一赘述了,如果有什么问题,欢迎下方留言

import 'dart:convert';import 'package:demo/model/model.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';class SecondListPage extends StatefulWidget {const SecondListPage({super.key});@overrideState<SecondListPage> createState() => _SecondListPageState();
}class _SecondListPageState extends State<SecondListPage> {final List<ListModel> _dataList = [];@overridevoid initState() {super.initState();_loadData();}_loadData() async {_dataList.clear();String jsonString = await rootBundle.loadString('assets/json/list.json');Map<String, dynamic> dict = jsonDecode(jsonString);_dataList.addAll(dict['data'].map<ListModel>((e) => ListModel.fromJson(e)).toList());setState(() {});}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('系统二级列表'),),body: SingleChildScrollView(child: Container(child: _buildExpansionPanel(),),),);}Widget _buildExpansionPanel() {return ExpansionPanelList.radio(initialOpenPanelValue: _dataList[0].id, //默认展开第一个expandIconColor:Colors.white, //设置icon的颜色,因为设置了canTapOnHeader: true,所以这里无效dividerColor: const Color.fromARGB(0, 233, 219, 219),expandedHeaderPadding: const EdgeInsets.all(0),materialGapSize: 0,// 设置底部阴影大小elevation: 0,children: _dataList.map<ExpansionPanelRadio>((item) {return ExpansionPanelRadio(canTapOnHeader: true, //点击区域backgroundColor: Colors.red,value: item.id!, //唯一标识headerBuilder: (context, isExpanded) {return Container(padding: const EdgeInsets.all(16.0),child: Text(item.title!,style: const TextStyle(color: Colors.white,),),);},body: ListView.builder(padding: const EdgeInsets.all(0),shrinkWrap: true,physics: const NeverScrollableScrollPhysics(),itemCount: item.subData!.length,itemExtent: 76.0,itemBuilder: (context, index) {return Container(color: Colors.green,child: ListTile(title: Text(item.subData![index].title!),),);},),);}).toList(),);}
}

自定义实现代码

import 'dart:convert';import 'package:demo/model/model.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';class SecondListViewPage extends StatefulWidget {const SecondListViewPage({super.key});@overrideState<SecondListViewPage> createState() => _SecondListViewPageState();
}class _SecondListViewPageState extends State<SecondListViewPage> {final List<ListModel> _dataList = []; //列表数据List listData = []; //处理是否展开和展开动画的数据final bool _isRadio = true; //是否只展开一个,默认是final double _cellHeight = 40.0; //title的高度final double _itemHeight = 40.0; //展开的cell的高度@overridevoid initState() {super.initState();_loadData();}@overridevoid dispose() {for (var listItem in listData) {listItem.animationController.dispose();}super.dispose();}_loadData() async {_dataList.clear();String jsonString = await rootBundle.loadString('assets/json/list.json');Map<String, dynamic> dict = jsonDecode(jsonString);_dataList.addAll(dict['data'].map<ListModel>((e) => ListModel.fromJson(e)).toList());for (var i = 0; i < _dataList.length; i++) {ListItem item = ListItem();//处理数据,给每个cell都新增一个isExpended属性item.isExpanded = i == 0 ? true : false; //默认第一个展开if (i == 0) {item.animationController.forward(); //第一个默认展开之后需要改变图片的旋转方向}listData.add(item);}setState(() {});}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('自定义二级列表'),),body: ListView.builder(itemCount: _dataList.length,itemBuilder: (context, index) {ListItem item = listData[index];return Column(children: [GestureDetector(onTap: () {setState(() {item.isExpanded = !item.isExpanded;if (_isRadio) {for (var i = 0; i < listData.length; i++) {if (i != index) {listData[i].isExpanded = false;}if (listData[i].isExpanded) {listData[i].animationController.forward();} else {listData[i].animationController.reverse();}}} else {if (listData[index].isExpanded) {listData[index].animationController.forward();} else {listData[index].animationController.reverse();}}});},child: Container(padding: const EdgeInsets.all(10.0),color: Colors.green,height: _cellHeight,child: Row(children: [// 显示title的widget,可以自定义Text('${_dataList[index].title}'),const SizedBox(width: 5.0),AnimatedBuilder(animation: item.animation,builder: (context, child) {return Transform.rotate(angle: item.animation.value * 3.14, // 180度对应的弧度值child: const Icon(Icons.arrow_drop_down), //这里可以替换成自定义的图片);},),],),),),AnimatedContainer(color: Colors.yellow,duration: const Duration(milliseconds: 200),height: item.isExpanded? _dataList[index].subData!.length * _itemHeight: 0.0,child: item.isExpanded? SingleChildScrollView(child: Column(children: _dataList[index].subData!.map((e) {return Container(alignment: Alignment.centerLeft,height: _itemHeight,child: Text(e.title!),);}).toList(),),): null,),],);},),);}
}class ListItem {bool isExpanded; //是否展开AnimationController animationController; //每个title展开或者关闭的时候,icon的旋转动画late Animation<double> animation; //ListItem({this.isExpanded = false}): animationController = AnimationController(duration: const Duration(milliseconds: 200),vsync: TickerProviderImpl(),) {animation = Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(parent: animationController,curve: Curves.easeInOut,),);}
}class TickerProviderImpl extends TickerProvider {@overrideTicker createTicker(TickerCallback onTick) {return Ticker(onTick);}
}

简书传送门
GitHub传送门

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/215881.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

容器化升级对服务有哪些影响?

容器技术是近几年计算机领域的热门技术&#xff0c;特别是随着各种云服务的发展&#xff0c;越来越多的服务运行在以 Docker 为代表的容器之内。 本文我们就来分享一下容器化技术相关的知识。 容器化技术简介 相比传统虚拟化技术&#xff0c;容器技术是一种更加轻量级的操作…

分治法求最大子列和

给定N个整数的序列{ A1, A2, …, AN}&#xff0c;其中可能有正数也可能有负数&#xff0c;找出其中连续的一个子数列&#xff08;不允许空序列&#xff09;&#xff0c;使它们的和尽可能大&#xff0c;如果是负数&#xff0c;则返回0。使用下列函数&#xff0c;完成分治法求最大…

CorelDRAW软件2024版本好用吗?有哪些功能优势

CorelDRAW是一款综合性强大的专业平面设计软件&#xff0c;其功能覆盖了矢量图形设计、高级文字编辑、精细绘图以及多页文档和页面设计。该软件不仅适用于广告设计、包装设计&#xff0c;还广泛应用于出版、网页设计和多媒体制作等多个领域。下面就给大家介绍一下CorelDRAW这款…

0012Java安卓程序设计-ssm记账app

文章目录 **摘要**目 录系统设计5.1 APP端&#xff08;用户功能&#xff09;5.2后端管理员功能模块开发环境 编程技术交流、源码分享、模板分享、网课分享 企鹅&#x1f427;裙&#xff1a;776871563 摘要 网络的广泛应用给生活带来了十分的便利。所以把记账管理与现在网络相…

arkts编译报错-arkts-limited-stdlib错误【Bug已完美解决-鸿蒙开发】

文章目录 项目场景:问题描述原因分析:解决方案:适配指导案例此Bug解决方案总结项目场景: arkts编译报错-arkts-limited-stdlib错误。 我用Deveco studio4.0 beta2开发应用,报arkts-limited-stdlib错误 报错内容为: ERROR: ArKTS:ERROR File: D:/prRevivw/3792lapplica…

Android 11.0 systemui锁屏页面时钟显示样式的定制功能实现

1.前言 在11.0的系统ROM定制化开发中,在进行systemui的相关开发中,当开机完成后在锁屏页面就会显示时间日期的功能,由于 开发产品的需求要求时间显示周几上午下午接下来就需要对锁屏显示时间日期的相关布局进行分析,然后实现相关功能 效果图如图: 2.systemui锁屏页面时钟显…

mysql原理--B+树索引

1.没有索引的查找 1.1.在一个页中的查找 (1). 以主键为搜索条件 可以在 页目录 中使用二分法快速定位到对应的槽&#xff0c;然后再遍历该槽对应分组中的记录即可快速找到指定的记录。 (2). 以其他列作为搜索条件 这种情况下只能从 最小记录 开始依次遍历单链表中的每条记录&am…

值得收藏的练习打字网站

本文对一些好用的练习打字的网站进行了汇总整理&#xff0c;方便大家使用 一&#xff1a;程序猿练习打字&#xff1a; 1.Typing Practice for Programmers http://Typing.io 是程序员的打字导师。它的练习课程基于开源代码&#xff0c;让你在不断的练习中提升自己的码字速度…

Python:核心知识点整理大全15-笔记

目录 ​编辑 7.3.2 删除包含特定值的所有列表元素 pets.py 7.3.3 使用用户输入来填充字典 mountain_poll.py 7.4 小结 第8章 函 数 8.1 定义函数 greeter.py 8.1.1 向函数传递信息 8.1.2 实参和形参 8.2.1 位置实参 2. 位置实参的顺序很重要 8.2.2 关键字实参 往…

计算机循环神经网络(RNN)

计算机循环神经网络&#xff08;RNN&#xff09; 一、引言 循环神经网络&#xff08;RNN&#xff09;是一种常见的深度学习模型&#xff0c;适用于处理序列数据&#xff0c;如文本、语音、时间序列等。RNN通过捕捉序列数据中的时间依赖关系和上下文信息&#xff0c;能够解决很…

CLIP的升级版Alpha-CLIP:区域感知创新与精细控制

为了增强CLIP在图像理解和编辑方面的能力&#xff0c;上海交通大学、复旦大学、香港中文大学、上海人工智能实验室、澳门大学以及MThreads Inc.等知名机构共同合作推出了Alpha-CLIP。这一创新性的突破旨在克服CLIP的局限性&#xff0c;通过赋予其识别特定区域&#xff08;由点、…

Could not resolve all dependencies for configuration ‘:app:androidApis‘.

android studio出现Could not resolve all dependencies for configuration ‘:app:androidApis’. 试过很多种方法&#xff0c;但是都不好使&#xff0c;不管怎么样都是提示如下报错&#xff1a; Using insecure protocols with repositories, without explicit opt-in, is un…

丹麦市场开发攻略,带你走进童话王国

说起安徒生&#xff0c;大家多多少少都知道&#xff0c;因为小时候读的安徒生童话书真的太有名了&#xff0c;但是大家可能不知道安徒生是丹麦的。丹麦是高度发达的国家&#xff0c;奉行自由贸易政策&#xff0c;市场潜力是非常不错的&#xff0c;而且中国是丹麦非常重要的贸易…

Python部分基础知识入门学习,十分钟快速上手

文章目录 一、基础语法二、变量类型三、运算符四、条件语句关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Python学习书籍四、Python工具包项目源码合集①Python工具包②Python实战案例③Python小游戏源码五、面试资料六、Python兼职渠道 一、…

初识 WebGPU 以及遇到 WebGPU not supported 错误的解决方法

初识 WebGPU 以及遇到 WebGPU not supported 错误的解决方法 WebGPU学习资源初识WebGPU遇到并解决问题在线示例 因公司需求&#xff0c;开始接触 WebGPU&#xff0c;偶然遇到问题&#xff0c;网上搜索无效&#xff0c;后来通过逐步判断&#xff0c;终于定位到问题&#xff0c;这…

【WPF 按钮点击后异步上传多文件code示例】

前言: WPF中按钮点击事件如何执行时间太长会导致整个UI线程卡顿&#xff0c;现象就是页面刷新卡住&#xff0c;点击其他按钮无反馈。如下是进行异步执行命令&#xff0c;并远程上传文件的代码。 ![异步上传文件](https://img-blog.csdnimg.cn/direct/20c071929b004dcf9223dee2…

听我的,日志还是得好好打!

日志这东西&#xff0c;平时看不出来什么&#xff0c;真要出了问题&#xff0c;那就是救命的稻草。这期就给大家分享一些日志相关的东西。 弄懂日志 SpringBoot项目启动日志 什么是日志&#xff1f; 日志&#xff0c;维基百科中对其的定义是一个或多个由服务器自动创建和维护…

【数学建模】《实战数学建模:例题与讲解》第十一讲-因子分析、聚类与主成分(含Matlab代码)

【数学建模】《实战数学建模&#xff1a;例题与讲解》第十一讲-因子分析、聚类与主成分&#xff08;含Matlab代码&#xff09; 基本概念聚类分析Q型聚类分析R型聚类分析 主成分分析因子分析 习题10.11. 题目要求2.解题过程3.程序4.结果 习题10.21. 题目要求2.解题过程3.程序4.结…

Java网络编程——安全网络通信

在网络上&#xff0c;信息在由源主机到目标主机的传输过程中会经过其他计算机。在一般情况下&#xff0c;中间的计算机不会监听路过的信息。但在使用网上银行或者进行信用卡交易时&#xff0c;网络上的信息有可能被非法分子监听&#xff0c;从而导致个人隐私的泄露。由于Intern…

ImmunityCanvas7.26安装详细教程

ImmunityCanvas7.26 大家想必都已经知道了Immunity Canvas7.26武器于2021年3月2日泄露了吧那我就废话不多说了。 很多人已经有了这款工具不得不说这工具很nice如果要买的话一年的话3万美金我的天我穷了。。 简单介绍 Immunity Canvas是美国ImmunitySec出品的安全漏洞检测工具…