Dart 使用Flatter中的Cloud Firestore创建无限列表
我目前正在将CloudFireStore与Streambuilder小部件一起使用,以便用Firestore文档填充ListView小部件Dart 使用Flatter中的Cloud Firestore创建无限列表,dart,google-cloud-firestore,flutter,Dart,Google Cloud Firestore,Flutter,我目前正在将CloudFireStore与Streambuilder小部件一起使用,以便用Firestore文档填充ListView小部件 new StreamBuilder<QuerySnapshot>( stream: Firestore.instance.collection('videos').limit(10).snapshots(), builder: (BuildContext context, AsyncSnapshot<QuerySnapshot>
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(),
);
},
);
新建StreamBuilder(
流:Firestore.instance.collection('videos').limit(10).snapshots(),
生成器:(BuildContext上下文,异步快照){
如果(!snapshot.hasData)返回新中心(
子项:新的CircularProgressIndicator(),
);
返回新的ListView(
子项:snapshot.data.documents.map((DocumentSnapshot文档){
新卡(子卡:…)
}).toList(),
);
},
);
但是,此设置仅允许查询第一个x结果(在本例中x=10),x是一个固定的数字,用户向下滚动时希望看到的卡片小部件数量迟早会超过x
现在是否可以查询第一个x结果,并在用户点击滚动阈值后从Cloud Firestore查询下一个x+10结果等等?
这将允许动态列表长度,这也有利于Firestore数据的使用 这当然是可能的,但是API中没有预先构建的内容 您必须记住第一页上的最后一个文档,然后使用该文档获取第二页文档
请参阅上的文档。我不确定是否可以使用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();
}
}
}
}
类提要扩展StatefulWidget{
提要({this.firestore});
最终消防仓库消防仓库;
@凌驾
_FeedState createState();
}
类_FeedState扩展状态{
滚动控制器;
文档快照_lastVisible;
bool_卸载;
CollectionReference get homeFeeds=>widget.firestore.collection('homefeed');
列表_data=新列表();
最终脚手架键=GlobalKey();
@凌驾
void initState(){
控制器=新的ScrollController()…addListener(\u scrollListener);
super.initState();
_isLoading=true;
_getData();
}
Future\u getData()异步{
//等待新的未来。延迟(新的持续时间(秒:5));
查询快照数据;
如果(_lastVisible==null)
data=wait widget.firestore
.collection('homefeed')
.orderBy('created_at',降序:true)
.限额(3)
.getDocuments();
其他的
data=wait widget.firestore
.collection('homefeed')
.orderBy('created_at',降序:true)
.startAfter([\u lastVisible['created\u at']]
.限额(3)
.getDocuments();
if(data!=null&&data.documents.length>0){
_lastVisible=data.documents[data.documents.length-1];
如果(已安装){
设置状态(){
_isLoading=false;
_data.addAll(数据文件);
});
}
}否则{
设置状态(()=>_isLoading=false);
scaffoldKey.currentState?.showSnackBar(
小吃条(
内容:Text('No more posts!'),
),
);
}
返回null;
}
@凌驾
小部件构建(构建上下文){
返回脚手架(
钥匙:脚手架钥匙,
appBar:新的appBar(),
正文:刷新指示器(
子项:ListView.builder(
控制器:控制器,
itemCount:_data.length+1,
itemBuilder:(\ux,int索引){
如果(索引<_数据长度){
最终文档快照文档=_数据[索引];
退回新货柜(
高度:200.0,
儿童:新文本(文件[‘问题]),
);
}
返回中心(
子对象:新的不透明度(
不透明度:_isLoading?1.0:0.0,
孩子:新尺寸的盒子(
宽度:32.0,
身高:32.0,
子项:新的CircularProgressIndicator()),
),
);
},
),
onRefresh:()异步{
_data.clear();
_lastVisible=null;
等待_getData();
},
),
);
}
@凌驾
无效处置(){
控制器。RemovelListener(_scrollListener);
super.dispose();
}
void_scrollListener(){
如果(!\u正在加载){
if(controller.position.pixels==controller.position.maxScrollExtent){
设置状态(()=>_isLoading=true);
_getData();
}
}
}
}
希望有帮助 这当然是可能的,但API中没有预先构建的内容。您必须记住第一页上的最后一个文档,然后使用该文档
startAfter()
,才能获得第二页文档。非常感谢您的回答!滚动阈值是否必须通过滚动控制器实现,或者无限列表最常用的解决方案是什么?刚刚在FirebaseUI中添加了一个分页适配器。为了获得灵感,我建议大家看看这个:这是为flatter@FrankvanPuffelen设计的,你不能用这个来回答。颤振没有所有的Java实现,这就是问题所在。人们必须开始真正回答有关stackoverflow的问题并停止寻找这些Medals此解决方案无法解决问题,就好像您试图动态更改“limit”值一样,流会进入“connection.waiting”状态一小会儿,在这一过程中,您将无法显示任何数据。此代码非常有趣,需要大量的解释,请注意,如果您将查询中的分页限制设置为小于屏幕大小,则scroll listener将永远不会被调用,并且无法加载数据,因此,要么您加载的内容超过用户屏幕,要么用户将仅限于第一页查询,这需要修复,为什么如果用户将scrolllistener刷出绑定,它永远不会被调用?