Flutter:使用来自 Firestore 的数据生成一个 Widget 列表

Flutter: generate a List of Widgets with data from Firestore

我希望我的屏幕显示 GridView 中有限数量的产品。 所有产品都存储在 Firebase Firestore 中,它们的图像在 Firebase 存储中。 为此,我使用 GridView.count,它的参数之一是 List<Widget> children。我想使用 List.generate 生成一个列表,每次都从 Firestore 中获取一个产品,并从存储中获取它的图像,以创建一个代表产品的小部件。 问题是从 Firebase 中获取产品是异步的,List.generategenerator 函数不能是 async。此外,我将 Future<List<Widget>> 而不是 List<Widget> 返回到 GridView.countchildren 参数 关于如何克服这个问题的任何想法?

这是我的代码:


GridView.count(
  primary: false,
  crossAxisCount: 2,
  padding: const EdgeInsets.all(20),
  crossAxisSpacing: 10,
  mainAxisSpacing: 10,
  //FIXME: The argument type 'Future<List<Widget>>' can't be assigned to the parameter type 'List<Widget>':
  children: _buildGridTileList(15),
)

Future<List<Widget>> _buildGridTileList(int count) async {
    var counterCollection = await FirebaseFirestore.instance.collection("Products").doc("Counter").get();
    var counterData = counterCollection.data();
    return List.generate(
      count,
      (index) async {
        //FIXME: Doesn't work beacuse generator cannot be async!!
        var avatarUrl = await FirebaseStorage.instance.ref('${counterData[index]}').child('${counterData[index]}').getDownloadURL();
        return Container(
          child: Center(
            child: NetworkImage(avatarUrl),
          ),
        );
      }
    );
  }

您的构建函数中不能有异步代码,因为它是组装小部件树以立即呈现到屏幕的函数,而您所做的是使用 StreamBuilder 小部件,它使您可以访问异步事件、流正在侦听来自 Firebase 的未来数据,并在异步事件到达时重建小部件树的该部分。这是它是如何完成的,这段代码应该接近你所需要的:

return StreamBuilder(
  stream: FirebaseFirestore.instance.collection("Products").snapshots(),
  builder:
  (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
  if (!snapshot.hasData) {
    return Container();
  } else {
    return GridView.count(
      primary: false,
      crossAxisCount: 2,
      padding: const EdgeInsets.all(20),
      crossAxisSpacing: 10,
      mainAxisSpacing: 10,
      children: List.generate(snapshot.data.docs.length, (index) {
        return Image.network(snapshot.data.docs[index].imageUrl);
        }),
      );
    }
  });
}