注意:我已经在ListView的延迟加载上看到了答案,但是这些答案是针对自定义API而非Firestore数据库的!
我有一个图书摘要应用程序,该应用程序从我的Firebase/Firestore
数据库中获取数据,然后使用ListView.builder
将其显示在StreamBuilder
中。
现在,我想延迟获取数据,这意味着当用户滚动列表时,所需的数据将被加载,而不是立即加载然后再懒惰地显示。
//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,
),
);
}
}),
);
}
答案 0 :(得分:0)
对延迟加载的描述似乎与分页是匹配的。这是在ListView.builder
此示例为Firestore pagination实现了Firebase官方文档的摘要。
在此演示中,有两种方法可以将数据加载到视图上。
ListView
RefreshIndicator
ListView
中的下一个文档。
ScrollController
用于确定用户是否点击了列表的底部。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())));
});
});
});
}
}
要解析文档中的数据,可以为对象创建一个模型。
class DocObj {
var documentName;
DocObj(DocObj doc) {
this.documentName = doc.getDocName();
}
dynamic getDocName() => documentName;
DocObj.setDocDetails(Map<dynamic, dynamic> doc)
: documentName = doc['name'];
}
该示例处理了来自Firestore的数据。
这是应用程序运行时的外观。
答案 1 :(得分:0)
我已经忍受了这一点,我所做的是我在列表视图生成器中添加了scrollcontroller,并且跟踪它是否到达列表的底部以及是否到达列表的底部,然后更新快照的限制。
我已经对此进行了实验并且效果很好。
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class Sample extends StatefulWidget {
@override
_SampleState createState() => _SampleState();
}
class _SampleState extends State<Sample> {
ScrollController _chatScrollController;
int loadMoreMsgs = 25; // at first it will load only 25
int a = 50; // 'loadMoreMsgs' will added by 'a' if we load more msgs in listview.
@override
void initState() {
_chatScrollController = ScrollController()
..addListener(() {
if (_chatScrollController.position.atEdge) {
if (_chatScrollController.position.pixels == 0)
print('ListView scrolled to top');
else {
setState(() {
loadMoreMsgs = loadMoreMsgs + a;
});
print('ListView scrolled to bottom');
}
}
});
super.initState();
}
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: FirebaseFirestore.instance.collection('CollectionName').limit(loadMoreMsgs).snapshots(),
builder: (context, snapshot) {
return ListView.builder(
controller: _chatScrollController,
itemBuilder: (context, index) {
return Text('This is a sample');
},
);
},
);
}
}
我只写了所需的代码才能理解。