在 Flutter 中使用 Cloud Firestore 创建无限列表
Posted
技术标签:
【中文标题】在 Flutter 中使用 Cloud Firestore 创建无限列表【英文标题】:Create infinite list with Cloud Firestore in flutter 【发布时间】: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()
与该文档一起获得第二页文档。
【参考方案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 实现,这是这里的问题。人们必须开始真正回答有关 *** 的问题并停止寻找那些奖牌 此解决方案无法解决问题,就像您尝试动态更改“限制”值一样,流会在短时间内进入“connection.waiting”状态,而当这种情况发生时,您将无法显示任何数据。以上是关于在 Flutter 中使用 Cloud Firestore 创建无限列表的主要内容,如果未能解决你的问题,请参考以下文章
查询时如何在 Flutter (Dart) 中使用变量 Cloud Firestore
Flutter如何根据某个值从firebase对列表进行分组
Firebase Cloud Firestore 在 Flutter 中获取地图数组
Flutter 中 Cloud Firestore 的 FieldValue.increment