You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 05:20:27