如何将 Firestore 文档从流传递到 Flutter 中的下一页?

How to pass a Firestore document from a stream to next page in Flutter?

我有一个列表视图,其中每个项目都是来自 firestore 集合的一个文档。我想点击项目并将文档信息传递到详细信息页面。

这是我在第一个流中检索文档信息的方式:

child: Text(streamSnapshot.data.docs[index]['event_title'],

这就是我尝试将数据发送到下一页的方式:

child: GestureDetector(
                          onTap: () {
                            Navigator.pushNamed(context, EventPage.id, arguments: streamSnapshot.data.docs[index]);
                          },

我不知道如何接收传递的数据:

    class _EventPageState extends State<EventPage> {
  @override

final db = FirebaseFirestore.instance;
  Widget build(BuildContext context) {
    final args = ModalRoute.of(context)!.settings.arguments;
    return CupertinoPageScaffold(
      navigationBar: CupertinoNavigationBar(
        middle: Text('event_title'),
      ),
      child: Column(

我知道我需要下一页的 StreamBuilder,但是您是否知道如何使该流仅显示传入的文档?

为什么不改用 Provider?它将帮助您避免样板代码,并且当您使用流时,它将让您以更好的方式处理信息。检查一下 here

我已经找到了这个问题的答案。我敢肯定有几种方法可以做到这一点,但这是我的方法:

关键是将 firestore 文档 ID 传递到下一页。在此示例代码中,我将 streamSnapshot.data.docs[index].id.toString() 作为参数传递给自定义小部件。我在那个小部件中找到了我命名的路线。

StreamBuilder(
    stream: FirebaseFirestore.instance
        .collection('events')
        .where('start_date', isGreaterThanOrEqualTo: DateTime.now())
        .snapshots(),
    builder: (context, AsyncSnapshot streamSnapshot) {

      if (!streamSnapshot.hasData) {
        return SizedBox(
          height: 250,
          child: Center(
            child: CircularProgressIndicator(),
          ),
        );
      } else
        return SizedBox(
          height: 250,
          child: ListView.builder(
            scrollDirection: Axis.horizontal,
            itemCount: streamSnapshot.data.docs.length,
            itemBuilder: (ctx, index) =>

                EventListHorizontalTile(

                //passes the document ID as a string down to the horizontally scrollable tile,
                //where we push a named route with the docID string as an argument

                firestoreDocID: streamSnapshot.data.docs[index].id.toString(),

                  image: streamSnapshot.data.docs[index]['main_image'],
                  name: streamSnapshot.data.docs[index]['name'],
              ),
          ),
        );
    }),

然后我创建了一个 class 作为参数通过命名路由传递。

class Events {
  final String firestoreDocID;

  Events({
    required this.firestoreDocID,

  });

}

现在,在我的 EventListHorizontalTile 小部件中:

class EventListHorizontalTile extends StatelessWidget {
  const EventListHorizontalTile({
    Key? key,

    required this.name,
    this.firestoreDocID = '',

  }) : super(key: key);

  final String name;
  final String firestoreDocID;

  @override
  Widget build(BuildContext context) {
return GestureDetector(

        onTap: () {

//Here I am pushing a named route with an argument, using that Events class I made earlier.

          Navigator.pushNamed(context, EventPage.id, arguments: Events(firestoreDocID: firestoreDocID));

        },

//child: The rest of the list tile widget

),

现在我们必须在 EventPage 中编写一些代码来接收参数。

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

  static String id = 'EventPage';

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

class _EventPageState extends State<EventPage> {
  @override
  Widget build(BuildContext context) {


//This is how we receive the argument.
    final args = ModalRoute.of(context)!.settings.arguments as Events;

    return CupertinoPageScaffold(
      navigationBar: CupertinoNavigationBar(),
      child: SingleChildScrollView(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [

//Some text to see if the string made it.
            Text(args.firestoreDocID),

]),
),
);
}
}

就是这样!在新页面中获得该文档 ID 后,您可以这样调用 Streambuilder

StreamBuilder(
              stream: FirebaseFirestore.instance
                  .collection('events')
                  .doc(args.firestoreDocID)
                  .snapshots(),