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

Flutter中如何将关联Firebase的ListView改为ListView.builder实现

Flutter对接Firestore将普通ListView替换为ListView.builder实现方案

完整修改后的可运行代码如下:

import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(FireApp());
}

class FireApp extends StatefulWidget {
  @override
  _FireAppState createState() => _FireAppState();
}
class _FireAppState extends State<FireApp> {
  final TextController = TextEditingController();
  // 存储每个条目的选中状态,key为Firestore文档ID
  final Map<String, bool> _checkedStatus = {};

  @override
  Widget build(BuildContext context) {
    CollectionReference groceries = FirebaseFirestore.instance.collection('groceries');

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: TextField(
            controller: TextController,
          ),
        ),
        body: Center(
          child: StreamBuilder<QuerySnapshot>(
            stream: groceries.orderBy('name').snapshots(),
            builder: (context, snapshot) {
              // 异常状态处理
              if (snapshot.hasError) {
                return const Text('加载数据失败');
              }
              // 加载状态处理
              if (snapshot.connectionState == ConnectionState.waiting) {
                return const CircularProgressIndicator();
              }
              // 有数据时渲染列表
              final docs = snapshot.data!.docs;
              return ListView.builder(
                itemCount: docs.length,
                itemBuilder: (context, index) {
                  final grocery = docs[index];
                  // 初始化当前条目的选中状态,默认未选中
                  if (!_checkedStatus.containsKey(grocery.id)) {
                    _checkedStatus[grocery.id] = false;
                  }
                  return Center(
                    child: Row(
                      children: [
                        Container(
                          color: Colors.red,
                          height: 50,
                          child: Text(grocery['name'])
                        ),
                        Checkbox(
                          materialTapTargetSize: MaterialTapTargetSize.padded,
                          value: _checkedStatus[grocery.id],
                          activeColor: Colors.black,
                          checkColor: Colors.greenAccent,
                          onChanged: (val) {
                            setState(() {
                              _checkedStatus[grocery.id] = val ?? false;
                            });
                            // 如果需要同步选中状态到Firestore,取消下面的注释即可
                            // groceries.doc(grocery.id).update({'isChecked': val ?? false});
                          }
                        )
                      ],
                    ),
                  );
                },
              );
            },
          ),
        ),
        floatingActionButton: FloatingActionButton(onPressed: () {
          groceries.add({
            'name': TextController.text,
            // 如果要将选中状态存储到Firestore,新增的时候默认添加对应字段
            // 'isChecked': false
          });
        },),
      ),
    );
  }
}

核心修改说明:

  • 状态边界处理:新增了加载中、加载失败的兜底逻辑,避免快照为空时直接调用!导致空引用崩溃
  • ListView.builder对接逻辑:直接将Firestore返回的docs列表长度绑定到itemCount,在itemBuilder中通过下标获取对应文档即可,无需一次性将所有文档转为Widget,长列表下性能提升明显
  • 选中逻辑修复:原代码共用全局isChecked变量会导致所有复选框同步修改,改为用Map存储每个文档ID对应的选中状态,实现单条目独立控制,如需持久化选中状态到云端,也可直接读写Firestore对应文档的布尔字段即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 08:36:04