代码之家  ›  专栏  ›  技术社区  ›  stefanmuke

使用flutter中的云火库创建无限列表

  •  10
  • stefanmuke  · 技术社区  · 6 年前

    我目前正在将CloudFireStore与StreamBuilder小部件一起使用,以便用FireStore文档填充ListView小部件。

    new StreamBuilder<QuerySnapshot>(
      stream: Firestore.instance.collection('videos').limit(10).snapshots(),
      builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
        if (!snapshot.hasData) return new Center(
          child: new CircularProgressIndicator(),
        );
        return new ListView(
          children: snapshot.data.documents.map((DocumentSnapshot document) {
            new Card(child: ...)
          }).toList(),
        );
      },
    );
    

    但是,此设置只允许查询第一个X结果(在本例中,X=10),X是一个固定的数字,用户在向下滚动时希望看到的卡片小部件的数量迟早会超过该数字。

    现在可以查询第一个x结果了吗?在用户点击滚动阈值后,可以从云FireStore等查询下一个x+10结果了吗?
    这将允许动态列表长度,这也将有利于FireStore数据消耗。

    2 回复  |  直到 6 年前
        1
  •  1
  •   Shyju M    5 年前

    我不确定使用StreamBuilder是否可行。我已经使用 startAfter

    class Feed extends StatefulWidget {
      Feed({this.firestore});
    
      final Firestore firestore;
    
      @override
      _FeedState createState() => _FeedState();
    }
    
    class _FeedState extends State<Feed> {
      ScrollController controller;
      DocumentSnapshot _lastVisible;
      bool _isLoading;
      CollectionReference get homeFeeds => widget.firestore.collection('homefeed');
      List<DocumentSnapshot> _data = new List<DocumentSnapshot>();
      final scaffoldKey = GlobalKey<ScaffoldState>();
    
      @override
      void initState() {
        controller = new ScrollController()..addListener(_scrollListener);
        super.initState();
        _isLoading = true;
        _getData();
      }
    
      Future<Null> _getData() async {
    //    await new Future.delayed(new Duration(seconds: 5));
        QuerySnapshot data;
        if (_lastVisible == null)
          data = await widget.firestore
              .collection('homefeed')
              .orderBy('created_at', descending: true)
              .limit(3)
              .getDocuments();
        else
          data = await widget.firestore
              .collection('homefeed')
              .orderBy('created_at', descending: true)
              .startAfter([_lastVisible['created_at']])
              .limit(3)
              .getDocuments();
    
        if (data != null && data.documents.length > 0) {
          _lastVisible = data.documents[data.documents.length - 1];
          if (mounted) {
            setState(() {
              _isLoading = false;
              _data.addAll(data.documents);
            });
          }
        } else {
          setState(() => _isLoading = false);
          scaffoldKey.currentState?.showSnackBar(
            SnackBar(
              content: Text('No more posts!'),
            ),
          );
        }
        return null;
      }
    
      @override
      Widget build(BuildContext context) {
    
        return Scaffold(
          key: scaffoldKey,
          appBar: new AppBar(),
          body: RefreshIndicator(
              child: ListView.builder(
            controller: controller,
            itemCount: _data.length + 1,
            itemBuilder: (_, int index) {
              if (index < _data.length) {
                final DocumentSnapshot document = _data[index];
                return new Container(
                  height: 200.0,
                  child: new Text(document['question']),
                );
              }
              return Center(
                child: new Opacity(
                  opacity: _isLoading ? 1.0 : 0.0,
                  child: new SizedBox(
                      width: 32.0,
                      height: 32.0,
                      child: new CircularProgressIndicator()),
                ),
              );
            },
          ),
            onRefresh: ()async{
                _data.clear();
                _lastVisible=null;
                await _getData();
            },
          ),
        );
      }
    
      @override
      void dispose() {
        controller.removeListener(_scrollListener);
        super.dispose();
      }
    
      void _scrollListener() {
        if (!_isLoading) {
          if (controller.position.pixels == controller.position.maxScrollExtent) {
            setState(() => _isLoading = true);
            _getData();
          }
        }
      }
    }
    

        2
  •  2
  •   Frank van Puffelen    6 年前

    这是绝对可能的,但是API中没有预构建的内容。

    你必须记住第一页的最后一个文档,然后 startAfter() 用那个文件来获取第二页的文件。

    请参阅上的文档 Paginating Data with Query Cursors .