Я опубликую свой код, я надеюсь, что кто-то опубликует лучшее решение, возможно, не лучшее, но оно работает.
В моем приложении реальное решение - изменить состояние списка при достижении вершины., остановить поток и показать старые сообщения.
Весь код (состояние)
class _MessageListState extends State<MessageList> {
List<DocumentSnapshot> _messagesSnapshots;
bool _isLoading = false;
final TextEditingController _textController = TextEditingController();
ScrollController listScrollController;
Message lastMessage;
Room room;
@override
void initState() {
listScrollController = ScrollController();
listScrollController.addListener(_scrollListener);
super.initState();
}
@override
Widget build(BuildContext context) {
room = widget.room;
return Flexible(
child: StreamBuilder<QuerySnapshot>(
stream: _isLoading
? null
: Firestore.instance
.collection('rooms')
.document(room.id)
.collection('messages')
.orderBy('timestamp', descending: true)
.limit(20)
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return LinearProgressIndicator();
_messagesSnapshots = snapshot.data.documents;
return _buildList(context, _messagesSnapshots);
},
),
);
}
Widget _buildList(BuildContext context, List<DocumentSnapshot> snapshot) {
_messagesSnapshots = snapshot;
if (snapshot.isNotEmpty) lastMessage = Message.fromSnapshot(snapshot[0]);
return ListView.builder(
padding: EdgeInsets.all(10),
controller: listScrollController,
itemCount: _messagesSnapshots.length,
reverse: true,
itemBuilder: (context, index) {
return _buildListItem(context, _messagesSnapshots[index]);
},
);
}
Widget _buildListItem(BuildContext context, DocumentSnapshot data) {
final message = Message.fromSnapshot(data);
Widget chatMessage = message.sender != widget.me.id
? Bubble(
message: message,
isMe: false,
)
: Bubble(
message: message,
isMe: true,
);
return Column(
children: <Widget>[chatMessage],
);
}
loadToTrue() {
_isLoading = true;
Firestore.instance
.collection('messages')
.reference()
.where('room_id', isEqualTo: widget.room.id)
.orderBy('timestamp', descending: true)
.limit(1)
.snapshots()
.listen((onData) {
print("Something change");
if (onData.documents[0] != null) {
Message result = Message.fromSnapshot(onData.documents[0]);
// Here i check if last array message is the last of the FireStore DB
int equal = lastMessage?.compareTo(result) ?? 1;
if (equal != 0) {
setState(() {
_isLoading = false;
});
}
}
});
}
_scrollListener() {
// if _scroll reach top
if (listScrollController.offset >=
listScrollController.position.maxScrollExtent &&
!listScrollController.position.outOfRange) {
final message = Message.fromSnapshot(
_messagesSnapshots[_messagesSnapshots.length - 1]);
// Query old messages
Firestore.instance
.collection('rooms')
.document(widget.room.id)
.collection('messages')
.where('timestamp', isLessThan: message.timestamp)
.orderBy('timestamp', descending: true)
.limit(20)
.getDocuments()
.then((snapshot) {
setState(() {
loadToTrue();
// And add to the list
_messagesSnapshots.addAll(snapshot.documents);
});
});
// For debug purposes
// key.currentState.showSnackBar(new SnackBar(
// content: new Text("Top reached"),
// ));
}
}
}
Наиболее важные методы:
_scrollListener
Когда я достигаю вершины, я запрашиваю старые сообщения и в setState я устанавливаю isLoading var в true и устанавливаю со старыми сообщениями массив, который я собираюсь показать.
_scrollListener() {
// if _scroll reach top
if (listScrollController.offset >=
listScrollController.position.maxScrollExtent &&
!listScrollController.position.outOfRange) {
final message = Message.fromSnapshot(
_messagesSnapshots[_messagesSnapshots.length - 1]);
// Query old messages
Firestore.instance
.collection('rooms')
.document(widget.room.id)
.collection('messages')
.where('timestamp', isLessThan: message.timestamp)
.orderBy('timestamp', descending: true)
.limit(20)
.getDocuments()
.then((snapshot) {
setState(() {
loadToTrue();
// And add to the list
_messagesSnapshots.addAll(snapshot.documents);
});
});
// For debug purposes
// key.currentState.showSnackBar(new SnackBar(
// content: new Text("Top reached"),
// ));
}
}
И loadToTrue, которые слушают, пока мы ищем старые сообщения.Если появляется новое сообщение, мы повторно активируем поток.
loadToTrue
loadToTrue() {
_isLoading = true;
Firestore.instance
.collection('rooms')
.document(widget.room.id)
.collection('messages')
.orderBy('timestamp', descending: true)
.limit(1)
.snapshots()
.listen((onData) {
print("Something change");
if (onData.documents[0] != null) {
Message result = Message.fromSnapshot(onData.documents[0]);
// Here i check if last array message is the last of the FireStore DB
int equal = lastMessage?.compareTo(result) ?? 1;
if (equal != 0) {
setState(() {
_isLoading = false;
});
}
}
});
}
Надеюсь, это поможет всем, у кого возникла такая же проблема (@Purus), и подождатьпока кто-нибудь не даст нам лучшее решение!