Flutter中如何按日期对列表进行分组归类
解决方案
要实现按日期分组展示交易记录(今日、明日各一个标题),需要先对接口返回的数据进行分组处理,再修改UI逻辑只在每组开头显示一次标题。以下是具体步骤和代码修改:
1. 定义交易数据模型
创建统一模型类存储每条交易的完整信息,避免分散列表难以处理:
class TransactionItem { final String detail; final String description; final String amount; final int timestamp; TransactionItem({ required this.detail, required this.description, required this.amount, required this.timestamp, }); }
2. 修改数据获取与分组逻辑
更新fetchlist函数,将接口返回的分散数据转换为TransactionItem列表,并按日期分组:
// 判断两个日期是否为同一天 bool isSameDay(DateTime date1, DateTime date2) { return date1.year == date2.year && date1.month == date2.month && date1.day == date2.day; } // 按日期分组交易记录 Map<String, List<TransactionItem>> groupTransactionsByDate(List<TransactionItem> items) { Map<String, List<TransactionItem>> groups = {}; final now = DateTime.now(); final today = DateTime(now.year, now.month, now.day); final tomorrow = today.add(const Duration(days: 1)); for (var item in items) { DateTime itemDate = DateTime.fromMillisecondsSinceEpoch(item.timestamp); String groupKey; if (isSameDay(itemDate, today)) { groupKey = "今日"; } else if (isSameDay(itemDate, tomorrow)) { groupKey = "明日"; } else { // 可选:处理其他日期,格式化为"MM/DD/YYYY" groupKey = "${itemDate.month}/${itemDate.day}/${itemDate.year}"; // 如果只需要显示今日和明日,可跳过该条记录: // continue; } groups.putIfAbsent(groupKey, () => []).add(item); } // 排序分组:今日优先,然后明日,最后其他日期(新的在前) List<String> sortedKeys = groups.keys.toList() ..sort((a, b) { if (a == "今日") return -1; if (b == "今日") return 1; if (a == "明日") return -1; if (b == "明日") return 1; DateTime dateA = DateTime.parse(a); DateTime dateB = DateTime.parse(b); return dateB.compareTo(dateA); }); return Map.fromEntries(sortedKeys.map((key) => MapEntry(key, groups[key]!))); } // 获取并分组数据 Future<Map<String, List<TransactionItem>>> fetchlist() async { final prefs = await SharedPreferences.getInstance(); var token = await prefs.getString("token"); var response = await networkHandler.get('/getalert', token); var data = jsonDecode(response); List detail = data['Detail']; List description = data['description']; List amount = data['amount']; List date = data['date']; List<TransactionItem> transactions = List.generate(detail.length, (index) { return TransactionItem( detail: detail[index].toString(), description: description[index].toString(), amount: amount[index].toString(), timestamp: date[index] as int, ); }); return groupTransactionsByDate(transactions); }
3. 更新UI展示逻辑
修改FutureBuilder,根据分组后的数据构建UI,每个分组只显示一次标题:
Container( margin: EdgeInsets.only( left: MediaQuery.of(context).size.width * 0.06, right: MediaQuery.of(context).size.width * 0.06, top: 10, ), child: FutureBuilder<Map<String, List<TransactionItem>>>( future: fetchlist(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: LoadingWidget()); } else if (snapshot.hasError) { return const Center(child: Text('加载数据出错')); } else if (snapshot.data == null || snapshot.data!.isEmpty) { return const Center(child: Text('暂无数据')); } else { List<Widget> listWidgets = []; snapshot.data!.forEach((groupName, items) { // 添加分组标题 listWidgets.add( Text( groupName, style: TextStyle( color: Theme.of(context).primaryColor.withOpacity(.6), fontSize: 18, fontWeight: FontWeight.bold, ), ), ); listWidgets.add(const SizedBox(height: 10)); // 添加分组内的所有交易项 for (var item in items) { listWidgets.add( // 替换为你的交易项UI组件,建议修改为接收TransactionItem参数 listviewItem(context, item), ); listWidgets.add(const SizedBox(height: 10)); } }); return ListView( shrinkWrap: true, children: listWidgets, ); } }, ), );
4. 调整交易项组件
将原listview函数修改为接收TransactionItem参数,避免依赖索引:
Widget listviewItem(BuildContext context, TransactionItem item) { // 替换为你原有的交易项UI代码,使用item的属性填充内容 return Container( padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12), decoration: BoxDecoration( border: Border(bottom: BorderSide(color: Colors.grey.shade200)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(item.description, style: const TextStyle(fontSize: 16)), const SizedBox(height: 4), Text(item.amount, style: TextStyle(color: Colors.green.shade700, fontWeight: FontWeight.bold)), Text(item.detail, style: TextStyle(color: Colors.grey.shade600, fontSize: 12)), ], ), ); }
关键改进点
- 不再为每条记录重复显示标题,按日期分组后只在每组开头显示一次
- 使用统一数据模型管理交易信息,提升代码可读性和维护性
- 完善加载、错误、空数据状态的处理逻辑
- 支持按日期排序分组,确保展示顺序符合预期
内容的提问来源于stack exchange,提问作者CINO
相关产品推荐
相关产品推荐

