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

Flutter如何在分类卡片显示ListView对应分类的条目总数

问题根因
  • 分类页build方法内初始化的cases列表是空数组,从未从Firestore拉取实际业务数据,读取length永远返回0
  • 三个分类卡片复用同一个空数组的长度属性,没有按照「优先级匹配+状态为待救援」的规则分别统计各分类的有效条目
  • 没有绑定数据实时监听链路,后台数据变更后卡片数字不会自动刷新
修复实现

直接在分类页接入和列表页同源的Firestore数据流,一次拉取cases集合全量快照后,按各分类的筛选规则本地统计数量,既能保证数字和列表页展示的条目完全对齐,也能支持数据实时更新。小数据量场景下本地筛选性能足够,不需要多次发起查询。

修正后的分类页完整代码:

class CaseListCategory extends StatefulWidget {
  const CaseListCategory({Key? key}) : super(key: key);

  @override
  _CaseListCategoryState createState() => _CaseListCategoryState();
}

class _CaseListCategoryState extends State<CaseListCategory> {
  /// Firestore案例集合引用,和列表页保持一致
  final CollectionReference _cases = FirebaseFirestore.instance.collection('cases');

  /// 统计指定优先级下、状态为待救援的案例总数
  int _calcValidCaseCount(QuerySnapshot snapshot, String targetPriority) {
    return snapshot.docs.where((doc) {
      final caseData = doc.data() as Map<String, dynamic>;
      // 筛选条件和列表页完全对齐,避免数字和实际列表不符
      return caseData['priority'] == targetPriority 
          && caseData['status'] == "Waiting for rescue";
    }).length;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        padding: const EdgeInsets.all(10),
        child: StreamBuilder<QuerySnapshot>(
          stream: _cases.snapshots(),
          builder: (context, snapshot) {
            // 数据加载时显示加载态
            if (!snapshot.hasData) {
              return const Center(child: CircularProgressIndicator());
            }

            // 提前计算三个分类的条目数
            final criticalNum = _calcValidCaseCount(snapshot.data!, "Critical");
            final moderateNum = _calcValidCaseCount(snapshot.data!, "Moderate");
            final lowNum = _calcValidCaseCount(snapshot.data!, "Low");

            return ListView(
              children: [
                // 严重优先级卡片
                GestureDetector(
                  onTap: () => Navigator.of(context).push(
                    MaterialPageRoute(builder: (context) => const CriticalCaseList()),
                  ),
                  child: Card(
                    elevation: 10,
                    color: Colors.red,
                    child: Padding(
                      padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 10),
                      child: Column(
                        children: [
                          const Text(
                            'CRITICAL',
                            style: TextStyle(letterSpacing: 1.0, fontSize: 20, fontWeight: FontWeight.bold),
                          ),
                          Text(
                            "$criticalNum",
                            style: const TextStyle(letterSpacing: 1.0, fontSize: 20, fontWeight: FontWeight.bold),
                          ),
                        ],
                      ),
                    ),
                  ),
                ),
                // 中等优先级卡片
                GestureDetector(
                  onTap: () => Navigator.of(context).push(
                    MaterialPageRoute(builder: (context) => const ModerateCaseList()),
                  ),
                  child: Card(
                    elevation: 10,
                    color: Colors.orange,
                    child: Padding(
                      padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 10),
                      child: Column(
                        children: [
                          const Text(
                            "MODERATE",
                            style: TextStyle(letterSpacing: 1.0, fontSize: 20, fontWeight: FontWeight.bold),
                          ),
                          Text(
                            "$moderateNum",
                            style: const TextStyle(letterSpacing: 1.0, fontSize: 20, fontWeight: FontWeight.bold),
                          ),
                        ],
                      ),
                    ),
                  ),
                ),
                // 低优先级卡片
                GestureDetector(
                  onTap: () => Navigator.of(context).push(
                    MaterialPageRoute(builder: (context) => const LowCaseList()),
                  ),
                  child: Card(
                    elevation: 10,
                    color: Colors.yellow,
                    child: Padding(
                      padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 10),
                      child: Column(
                        children: [
                          const Text(
                            'LOW',
                            style: TextStyle(letterSpacing: 1.0, fontSize: 20, fontWeight: FontWeight.bold),
                          ),
                          Text(
                            "$lowNum",
                            style: const TextStyle(letterSpacing: 1.0, fontSize: 20, fontWeight: FontWeight.bold),
                          ),
                        ],
                      ),
                    ),
                  ),
                ),
              ],
            );
          },
        ),
      ),
    );
  }
}

补充说明:如果后续cases集合数据量超过1000条,不建议继续使用拉全量本地筛选的方案,可以改用Firestore的count()查询,按三个分类的筛选条件分别发起计数请求,减少不必要的流量消耗。如果修改了列表页的条目筛选规则,必须同步更新_calcValidCaseCount里的判断逻辑,避免卡片数字和实际列表条目数不一致。

内容的提问来源于stack exchange,提问作者mihab

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 09:57:16