【问题标题】:Create infinite list with Cloud Firestore in flutter在 Flutter 中使用 Cloud Firestore 创建无限列表
【发布时间】:2018-11-06 09:08:21
【问题描述】:

我目前正在将 Cloud Firestore 与 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 个结果,并在用户达到滚动阈值后从 Cloud Firestore 查询下一个 x+10 个结果等等?
这将允许动态列表长度,这也将有利于 Firestore 数据消耗。

【问题讨论】:

  • 这绝对是可能的,但 API 中没有预先构建任何内容。您必须记住第一页上的最后一个文档,然后 startAfter() 与该文档一起获得第二页文档。

标签: dart google-cloud-firestore flutter


【解决方案1】:

我不确定 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】:

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

您必须记住第一页上的最后一个文档,然后 startAfter() 与该文档一起获取第二页文档。

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

【讨论】:

  • 非常感谢您的回答!滚动阈值是否必须使用滚动控制器来实现,或者无限列表最常用的解决方案是什么?
  • 一个分页适配器刚刚添加到 FirebaseUI。为了获得灵感,我建议您查看:github.com/firebase/FirebaseUI-Android/tree/master/…
  • 这是为颤振@FrankvanPuffelen 准备的,你不能试图回答这个问题。 Flutter 没有所有的 Java 实现,这是这里的问题。人们必须开始真正回答有关 stackoverflow 的问题并停止寻找那些奖牌
  • 此解决方案无法解决问题,就像您尝试动态更改“限制”值一样,流会在短时间内进入“connection.waiting”状态,而当这种情况发生时,您将无法显示任何数据。
猜你喜欢
  • 1970-01-01
  • 2020-05-10
  • 2020-04-26
  • 2020-11-27
  • 2020-03-30
  • 2021-05-05
  • 2019-12-01
  • 1970-01-01
  • 2022-01-17
相关资源
最近更新 更多