Flutter:来自Firestore的延迟加载数据 [英] Flutter: Lazy Load data from firestore

查看:55
本文介绍了Flutter:来自Firestore的延迟加载数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:我已经在ListView的延迟加载上看到了答案,但是这些答案是针对自定义API而不是Firestore数据库的!

我有一个图书摘要应用程序,该应用程序从我的 Firebase/Firestore 数据库中获取数据,然后使用包装在内的 ListView.builder 进行显示StreamBuilder .

现在,我想懒惰地获取数据,这意味着当用户滚动列表时,所需的数据将被加载,而不是立即加载然后懒惰地显示.

 //用于显示数据的小部件:窗口小部件feed(){返回容器(宽度:deviceWidth,高度:deviceHeight/3,子级:StreamBuilder(流:Firestore.instance.collection('feedItem').orderBy('feedId',降序:true).snapshots(),builder:(BuildContext上下文,AsyncSnapshot快照){如果(snapshot.hasData){int totalLength = snapshot.data.documents.length;返回ListView.builder(scrollDirection:Axis.horizo​​ntal,itemCount:totalLength>10个?10:totalLength,itemBuilder:(BuildContext上下文,整数索引){返回容器(宽度:deviceWidth/2.5,子代:GestureDetector(onTap:(){Navigator.push(语境,MaterialPageRoute(builder:(BuildContext上下文)=>FeedIntro(snapshot.data.documents [((totalLength-1)-index)] ['feedId']))));},子卡:子:列(mainAxisAlignment:MainAxisAlignment.start,子代:< Widget> [容器(//宽度:150,高度:150,前景色装饰:BoxDecoration(图片:DecorationImage(图片:NetworkImage(snapshot.data.documents [index] ['feedImage'],),适合:BoxFit.fill)),),中心(孩子:填充(填充:const EdgeInsets.all(8.0),子级:文本(snapshot.data.documents [index] ['title']),)),],)),),);},);}否则,如果(snapshot.hasError){return Center(child:Text('对不起,出问题了!'));} 别的 {退货中心(子代:SizedBox(子级:CircularProgressIndicator(),宽度:50,高度:50,),);}}),);} 

解决方案

您的延迟加载说明似乎与分页匹配.这是一个使用Firestore在 ListView.builder

中进行分页的简单演示

此示例为

这是应用程序运行时的外观.

Note: I have already seen answers on Lazy Load of ListView but those are for custom API not firestore database!

I have a books summary app, App fetches data from my Firebase/Firestore database and then display it using a ListView.builder which is wrapped inside a StreamBuilder.

Now, I want to fetch data lazily, I mean as the user scrolls through the List the required data gets loaded rather than loading data at once and then displaying it lazily.

//The Widget used to display data:

Widget feed() {
  return Container(
    width: deviceWidth,
    height: deviceHeight / 3,
    child: StreamBuilder(
        stream: Firestore.instance
            .collection('feedItem')
            .orderBy('feedId', descending: true)
            .snapshots(),

        builder: (BuildContext context, AsyncSnapshot snapshot) {
          if (snapshot.hasData) {
            int totalLength = snapshot.data.documents.length;
            return ListView.builder(
              scrollDirection: Axis.horizontal,
              itemCount: totalLength > 10 ? 10 : totalLength,
              itemBuilder: (BuildContext context, int index) {
                return Container(
                  width: deviceWidth / 2.5,
                  child: GestureDetector(
                    onTap: () {
                      Navigator.push(
                          context,
                          MaterialPageRoute(
                              builder: (BuildContext context) => FeedIntro(
                                  snapshot.data.documents[
                                      ((totalLength - 1) - index)]['feedId'])));
                    },
                    child: Card(
                        child: Column(
                      mainAxisAlignment: MainAxisAlignment.start,
                      children: <Widget>[
                        Container(
                          // width: 150,
                          height: 150,
                          foregroundDecoration: BoxDecoration(
                              image: DecorationImage(
                                  image: NetworkImage(
                                    snapshot.data.documents[index]['feedImage'],
                                  ),
                                  fit: BoxFit.fill)),
                        ),
                        Center(
                            child: Padding(
                          padding: const EdgeInsets.all(8.0),
                          child: Text(snapshot.data.documents[index]['title']),
                        )),
                      ],
                    )),
                  ),
                );
              },
            );
          } else if (snapshot.hasError) {
            return Center(child: Text('Sorry Something went wrong!'));
          } else {
            return Center(
              child: SizedBox(
                child: CircularProgressIndicator(),
                width: 50,
                height: 50,
              ),
            );
          }
        }),
  );
}

解决方案

The description of your lazy loading seems to match what pagination is. Here's a simple demo using Firestore with pagination in a ListView.builder

This sample implements snippets from Firebase official doc for Firestore pagination.

There are two ways to load the data on the view in this demo.

  • Refresh the entire ListView using RefreshIndicator
  • Scroll down to hit the bottom of the list to load up the next documents in the ListView. ScrollController is used to determine if the user has hit the bottom part of the list.

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

import 'DocObj.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  var scrollController = ScrollController();

  @override
  void initState() {
    super.initState();
    getDocuments();
    scrollController.addListener(() {
      if (scrollController.position.atEdge) {
        if (scrollController.position.pixels == 0)
          print('ListView scroll at top');
        else {
          print('ListView scroll at bottom');
          getDocumentsNext(); // Load next documents
        }
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: listDocument.length != 0
            ? RefreshIndicator(
                child: ListView.builder(
                  physics: AlwaysScrollableScrollPhysics(),
                  controller: scrollController,
                  itemCount: listDocument.length,
                  itemBuilder: (context, index) {
                    return ListTile(
                      title: Text('${listDocument[index].documentName}'),
                    );
                  },
                ),
                onRefresh: getDocuments, // Refresh entire list
              )
            : CircularProgressIndicator(),
      ),
    );
  }

  List<DocObj> listDocument;
  QuerySnapshot collectionState;
  // Fetch first 15 documents
  Future<void> getDocuments() async {
    listDocument = List();
    var collection = FirebaseFirestore.instance
        .collection('sample_pagination')
        .orderBy("name")
        .limit(15);
    print('getDocuments');
    fetchDocuments(collection);
  }

  // Fetch next 5 documents starting from the last document fetched earlier
  Future<void> getDocumentsNext() async {
    // Get the last visible document
    var lastVisible = collectionState.docs[collectionState.docs.length-1];
    print('listDocument legnth: ${collectionState.size} last: $lastVisible');

    var collection = FirebaseFirestore.instance
        .collection('sample_pagination')
        .orderBy("name").startAfterDocument(lastVisible).limit(5);

    fetchDocuments(collection);
  }

  fetchDocuments(Query collection){
    collection.get().then((value) {
      collectionState = value; // store collection state to set where to start next
      value.docs.forEach((element) {
        print('getDocuments ${element.data()}');
        setState(() {
          listDocument.add(DocObj(DocObj.setDocDetails(element.data())));
        });
      });
    });
  }
}

To parse the data inside the document, you can create a model for your object.

class DocObj {
  var documentName;

  DocObj(DocObj doc) {
    this.documentName = doc.getDocName();
  }

  dynamic getDocName() => documentName;

  DocObj.setDocDetails(Map<dynamic, dynamic> doc)
      : documentName = doc['name'];
}

The sample handles this data from Firestore.

Here's how the app looks when running.

这篇关于Flutter:来自Firestore的延迟加载数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆