Flutter实现类安卓最近通话列表UI:无额外包优化代码
优化Flutter分组交易列表UI实现
原实现的核心问题在于直接在ListView.builder中维护临时列表和状态,容易因多次触发build导致数据混乱,且渲染逻辑冗余。更合理的方式是先对数据按日期分组,再基于分组后的数据构建UI,逻辑更清晰且性能更优。
优化步骤与代码实现
1. 数据分组逻辑
先将原始交易数据按日期分组,把同一日期的交易归为一组。可以在initState中完成分组(如果是StatefulWidget),避免每次build重复计算:
// 按日期分组的函数 Map<String, List<Trans>> groupTransByDate(List<Trans> data) { final Map<String, List<Trans>> groupedData = {}; final dateFormat = DateFormat('yMMMMd'); for (final trans in data) { final dateStr = dateFormat.format(trans.date); groupedData.putIfAbsent(dateStr, () => []).add(trans); } return groupedData; }
2. 完整Widget实现
使用分组后的数据构建列表,每个列表项对应一个日期分组,包含日期标题和该日期的所有交易项容器:
class TransListScreen extends StatefulWidget { const TransListScreen({super.key}); @override State<TransListScreen> createState() => _TransListScreenState(); } class _TransListScreenState extends State<TransListScreen> { late final Map<String, List<Trans>> _groupedTrans; @override void initState() { super.initState(); // 初始化时完成数据分组 _groupedTrans = groupTransByDate(data); } Map<String, List<Trans>> groupTransByDate(List<Trans> data) { final Map<String, List<Trans>> groupedData = {}; final dateFormat = DateFormat('yMMMMd'); for (final trans in data) { final dateStr = dateFormat.format(trans.date); groupedData.putIfAbsent(dateStr, () => []).add(trans); } return groupedData; } @override Widget build(BuildContext context) { // 将分组的Map转换为列表,方便ListView.builder遍历 final groupedList = _groupedTrans.entries.toList(); return SafeArea( child: Scaffold( body: Padding( padding: const EdgeInsets.all(8.0), child: ListView.builder( itemCount: groupedList.length, itemBuilder: (context, index) { final entry = groupedList[index]; final dateTitle = entry.key; final transList = entry.value; return Column( children: [ // 日期标题容器 Container( height: 40, alignment: Alignment.center, child: Text(dateTitle), ), // 交易项容器 Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(8.0), color: Colors.grey.shade300, ), child: Column( children: List.generate( transList.length, (tileIndex) => CustomTransTileWidget( showDivider: tileIndex != transList.length - 1, trans: transList[tileIndex], ), ), ), ), // 分组之间的间隔 const SizedBox(height: 8), ], ); }, ), ), ), ); } }
3. 原Trans类与测试数据保持不变
class Trans { String id; double amount; String title; bool isExpense; DateTime date; Trans({ required this.id, required this.title, this.isExpense = false, required this.amount, required this.date, }); } List<Trans> data = [ Trans(id: '1', title: 'Food', amount: 100.0, date: DateTime(2023,08,01)), Trans(id: '2', title: 'Food', amount: 130.0, date: DateTime(2023,08,01)), Trans(id: '3', title: 'Food', amount: 150.0, date: DateTime(2023,08,01)), Trans(id: '4', title: 'Food', amount: 300.0, date: DateTime(2023,08,02), isExpense: false), Trans(id: '5', title: 'Food', amount: 200.0, date: DateTime(2023,08,02)), ];
优化优势
- 逻辑清晰:先分组再渲染,避免在itemBuilder中维护复杂的临时状态
- 性能更优:仅在初始化时分组一次,不会因build重复计算;ListView的itemCount是分组数量,减少不必要的组件渲染
- 可维护性强:分组逻辑独立,后续修改分组规则仅需调整
groupTransByDate函数
内容的提问来源于stack exchange,提问作者Irfan Ganatra
相关产品推荐
相关产品推荐

