如何使用 Flutter 从 Firestore 获取 ListView 的无限滚动
How to get an infinite scroll with ListView from Firestore with Flutter
我在 Flutter 中使用 Firestore 和 ListView。
对于列表中的某些项目,每个项目都可以正常工作,但我向下滚动的距离超出了看到的限制,我收到了很多消息:"the method was called on null"。
似乎 ListView.builder 没有正确处理来自 Firebase 或类似东西的所有日期请求。
这是代码:
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:father_home_flutter/screen_audio_selected.dart';
import 'package:father_home_flutter/model/utils.dart';
class AudioScreenList extends StatelessWidget {
static const String _collectionRussian = 'speech-ru';
static const String _loadingTextRussian = 'Loading...';
static const String _speechTitle = 'speechTitle';
static const String _speechSubtitle = 'speechSubtitle';
static const String _audioLink = 'audioLink';
static const String _pastorCode = 'pastorCode';
static const String _pastorName = 'pastorName';
static const String _id = "id";
@override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder(
stream: Firestore.instance
.collection(_collectionRussian)
.limit(100)
.orderBy(_id, descending: true)
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData)
return const Center(
child: Text(
_loadingTextRussian,
style: TextStyle(fontSize: 25.0, color: Colors.grey),
));
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (BuildContext context, int i) =>
_buildRow(context, snapshot.data.documents[i]),
);
}));
}
Widget _buildRow(BuildContext context, DocumentSnapshot document) {
return Container(
margin: const EdgeInsets.fromLTRB(0.0, 8.0, 0.0, 0.0),
height: 90.0,
child: ListTile(
leading: Padding(
padding: EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0),
child: Hero(
tag: document[_audioLink],
child: new ClipOval(
child: Container(
width: 70.0,
height: 70.0,
child: Image.asset(
Utils.getImagePastor(document[_pastorCode]),
fit: BoxFit.cover,
),
)))),
title: Text(document[_speechTitle]),
subtitle:
Text(document[_speechSubtitle] + " - " + document[_pastorName]),
onTap: () => onPressed(context, document[_speechTitle],
document[_pastorCode], document[_audioLink])));
}
onPressed(BuildContext context, String speechTitle, String pastorCode,
String audioLink) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
ScreenAudioSelected(speechTitle, pastorCode, audioLink)));
}
}
这是模拟器上的问题:
我在网上四处寻找处理它的方法,但我只是找到了像这个例子一样模拟服务器请求的例子https://flutter-academy.com/flutter-listview-infinite-scrolling/
有人遇到过同样的问题或知道如何解决吗?
好的,在网上看了之后我找到了解决这个问题的方法,多亏了这个
如果有人需要,我在这里写下完整的代码:
class AudioScreenList extends StatefulWidget {
@override
_AudioScreenListState createState() => _AudioScreenListState();
}
class _AudioScreenListState extends State<AudioScreenList> {
bool isPerformingRequest = false;
static const String _collectionRussian = 'speech-ru';
static const String _loadingTextRussian = 'Loading...';
static const String _speechTitle = 'speechTitle';
static const String _speechSubtitle = 'speechSubtitle';
static const String _audioLink = 'audioLink';
static const String _pastorCode = 'pastorCode';
static const String _pastorName = 'pastorName';
static const String _id = "id";
@override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder(
stream: Firestore.instance
.collection(_collectionRussian)
.orderBy(_id, descending: true)
.snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData)
return const Center(
child: Text(
_loadingTextRussian,
style: TextStyle(fontSize: 25.0, color: Colors.grey),
));
return ListView(children: getExpenseItems(snapshot));
}));
}
getExpenseItems(AsyncSnapshot<QuerySnapshot> snapshot) {
return snapshot.data.documents
.map((doc) => new Container(
margin: const EdgeInsets.fromLTRB(0.0, 8.0, 0.0, 0.0),
child: ListTile(
leading: Padding(
padding: EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0),
child: Hero(
tag: doc[_audioLink],
child: new ClipOval(
child: Container(
width: 70.0,
height: 70.0,
child: Image.asset(
Utils.getImagePastor(doc[_pastorCode]),
fit: BoxFit.cover,
),
)))),
title: new Text(doc[_speechTitle]),
subtitle: new Text(doc[_speechSubtitle].toString() +
" - " +
doc[_pastorName].toString()),
onTap: () => onPressed(context, doc[_speechTitle],
doc[_pastorCode], doc[_audioLink]))))
.toList();
}
onPressed(BuildContext context, String speechTitle, String pastorCode,
String audioLink) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
ScreenAudioSelected(speechTitle, pastorCode, audioLink)));
}
}
我在 Flutter 中使用 Firestore 和 ListView。 对于列表中的某些项目,每个项目都可以正常工作,但我向下滚动的距离超出了看到的限制,我收到了很多消息:"the method was called on null"。 似乎 ListView.builder 没有正确处理来自 Firebase 或类似东西的所有日期请求。
这是代码:
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:father_home_flutter/screen_audio_selected.dart';
import 'package:father_home_flutter/model/utils.dart';
class AudioScreenList extends StatelessWidget {
static const String _collectionRussian = 'speech-ru';
static const String _loadingTextRussian = 'Loading...';
static const String _speechTitle = 'speechTitle';
static const String _speechSubtitle = 'speechSubtitle';
static const String _audioLink = 'audioLink';
static const String _pastorCode = 'pastorCode';
static const String _pastorName = 'pastorName';
static const String _id = "id";
@override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder(
stream: Firestore.instance
.collection(_collectionRussian)
.limit(100)
.orderBy(_id, descending: true)
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData)
return const Center(
child: Text(
_loadingTextRussian,
style: TextStyle(fontSize: 25.0, color: Colors.grey),
));
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (BuildContext context, int i) =>
_buildRow(context, snapshot.data.documents[i]),
);
}));
}
Widget _buildRow(BuildContext context, DocumentSnapshot document) {
return Container(
margin: const EdgeInsets.fromLTRB(0.0, 8.0, 0.0, 0.0),
height: 90.0,
child: ListTile(
leading: Padding(
padding: EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0),
child: Hero(
tag: document[_audioLink],
child: new ClipOval(
child: Container(
width: 70.0,
height: 70.0,
child: Image.asset(
Utils.getImagePastor(document[_pastorCode]),
fit: BoxFit.cover,
),
)))),
title: Text(document[_speechTitle]),
subtitle:
Text(document[_speechSubtitle] + " - " + document[_pastorName]),
onTap: () => onPressed(context, document[_speechTitle],
document[_pastorCode], document[_audioLink])));
}
onPressed(BuildContext context, String speechTitle, String pastorCode,
String audioLink) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
ScreenAudioSelected(speechTitle, pastorCode, audioLink)));
}
}
这是模拟器上的问题:
我在网上四处寻找处理它的方法,但我只是找到了像这个例子一样模拟服务器请求的例子https://flutter-academy.com/flutter-listview-infinite-scrolling/
有人遇到过同样的问题或知道如何解决吗?
好的,在网上看了之后我找到了解决这个问题的方法,多亏了这个
如果有人需要,我在这里写下完整的代码:
class AudioScreenList extends StatefulWidget {
@override
_AudioScreenListState createState() => _AudioScreenListState();
}
class _AudioScreenListState extends State<AudioScreenList> {
bool isPerformingRequest = false;
static const String _collectionRussian = 'speech-ru';
static const String _loadingTextRussian = 'Loading...';
static const String _speechTitle = 'speechTitle';
static const String _speechSubtitle = 'speechSubtitle';
static const String _audioLink = 'audioLink';
static const String _pastorCode = 'pastorCode';
static const String _pastorName = 'pastorName';
static const String _id = "id";
@override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder(
stream: Firestore.instance
.collection(_collectionRussian)
.orderBy(_id, descending: true)
.snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData)
return const Center(
child: Text(
_loadingTextRussian,
style: TextStyle(fontSize: 25.0, color: Colors.grey),
));
return ListView(children: getExpenseItems(snapshot));
}));
}
getExpenseItems(AsyncSnapshot<QuerySnapshot> snapshot) {
return snapshot.data.documents
.map((doc) => new Container(
margin: const EdgeInsets.fromLTRB(0.0, 8.0, 0.0, 0.0),
child: ListTile(
leading: Padding(
padding: EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0),
child: Hero(
tag: doc[_audioLink],
child: new ClipOval(
child: Container(
width: 70.0,
height: 70.0,
child: Image.asset(
Utils.getImagePastor(doc[_pastorCode]),
fit: BoxFit.cover,
),
)))),
title: new Text(doc[_speechTitle]),
subtitle: new Text(doc[_speechSubtitle].toString() +
" - " +
doc[_pastorName].toString()),
onTap: () => onPressed(context, doc[_speechTitle],
doc[_pastorCode], doc[_audioLink]))))
.toList();
}
onPressed(BuildContext context, String speechTitle, String pastorCode,
String audioLink) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
ScreenAudioSelected(speechTitle, pastorCode, audioLink)));
}
}