How do i add more items on scroll in the listview?
1,189
Not sure if the following will help, but here's what I did in my flutter app. Pay special attention to the _onScroll function at the bottom.
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../blocs/feed_bloc/feed_events.dart';
import '../../blocs/feed_bloc/bloc.dart';
import '../../blocs/feed_bloc/feed_state.dart';
import './post.dart';
import '../loader.dart';
class Feed extends StatefulWidget {
Feed({ Key key }): super(key: key);
@override
_FeedState createState() => _FeedState();
}
class _FeedState extends State<Feed> {
final _scrollController = ScrollController();
final _scrollThreshold = 300.0;
FeedBloc _feedBloc;
_FeedState();
@override
void initState() {
super.initState();
_scrollController.addListener(_onScroll);
_feedBloc = BlocProvider.of<FeedBloc>(context);
}
@override
Widget build(BuildContext context) {
return BlocBuilder<FeedBloc, FeedState>(
builder: (context, state) {
if (state is FeedUninitialized) {
_feedBloc.add(Init());
return Loader();
}
if (state is FeedLoading) {
return Loader();
}
if (state is FeedLoaded) {
return new RefreshIndicator(
child: ListView(
controller: _scrollController,
// Important: Remove any padding from the ListView.
padding: EdgeInsets.zero,
children: state.posts.map((post) {
return Post(
postModel: state.postMap[post]
);
}).toList(),
),
onRefresh: () {
_feedBloc.add(Refresh());
return new Future.delayed(new Duration(seconds: 1));
},
);
}
return Center(
child: SizedBox(
height: 33,
child: Text(
'Sorry, there was a problem loading the feed.',
style: TextStyle( color: Colors.white)
),
),
);
}
);
}
int lastScroll = 0;
void _onScroll() {
if (new DateTime.now().millisecondsSinceEpoch - lastScroll > 1000) {
lastScroll = new DateTime.now().millisecondsSinceEpoch;
final maxScroll = _scrollController.position.maxScrollExtent;
final currentScroll = _scrollController.position.pixels;
if (maxScroll - currentScroll <= _scrollThreshold) {
_feedBloc.add(Fetch());
}
}
}
}
I think what you need is startAfterDocument. See below...
Future<Map<String, dynamic>> getPosts({PostModel parent, PostModel lastPost}) async {
// First, we create the initial query.
// We pass in the parent key if there is one.
Query query = Firestore.instance
.collection('posts');
if (parent != null) {
query = query.where('parentId', isEqualTo: parent.key);
} else {
query = query.where('parentId', isNull: true);
}
query = query.orderBy('timestamp', descending: true);
// If we want to start at a certain doc (user is scrolling throught he feed)
// then we specify to start after a certain doc
if (lastPost != null) {
query = query.startAfterDocument(lastPost.rawDoc);
}
// Execute the query
final results = await query
.limit(18)
.getDocuments();
// Create some Lists/Maps we're going to need
List<String> posts = new List<String>();
Map<String, PostModel> postMap = new Map<String, PostModel>();
Map<String, bool> likeMap = new Map<String, bool>();
// Convienience/Brevity
final List<DocumentSnapshot> documents = results.documents;
final int numDocs = documents.length;
if (numDocs > 0) {
final firstDoc = results.documents[0].data;
final lastDoc = results.documents[numDocs-1].data;
// Get all your likes for a certain date range that aligns with the
// documents we just retrieved
likeMap = await getLikes(firstDoc['postCreated'], lastDoc['postCreated']);
}
// Loop through, and create all the PostModels
for (int i = 0; i < numDocs; i++) {
DocumentSnapshot doc = documents[i];
PostModel post = snapshotToPostModel(doc, likeMap[doc.documentID]);
postMap[doc.documentID] = post;
posts.add(post.key);
}
final Map<String, dynamic> res = new Map<String, dynamic>();
res['posts'] = posts;
res['postMap'] = postMap;
return res;
}
Author by
alex
Updated on December 19, 2022Comments
-
alex over 1 year
This code here currently loads all the brews that are stored in the Firestore collection.. How can i load initially just 10 brews and then later on when the user scrolls down and reaches to the end of the list of 10 brews..it should load 10 more after the last brew..and the brews should be sorted according to the timestamp.
class BrewList extends StatefulWidget { @override _BrewListState createState() => _BrewListState(); } class _BrewListState extends State<BrewList> { List<Brew> brews = []; ScrollController _controller = ScrollController(); @override void initState() { _startFirst(); super.initState(); _controller.addListener(_scrollListener); } _scrollListener() { setState(() { if (_controller.position.atEdge) { if (_controller.position.pixels == 0) { } else { } } }); } _startFirst() async { brews = await DatabaseService().brews ?? []; setState(() { brews = brews; }); } @override Widget build(BuildContext context) { Future<void> _refreshBrews() async { List<Brew> tempList = await DatabaseService().brews; setState(() { brews = tempList; }); print(brews); } return RefreshIndicator( onRefresh: _refreshBrews, child: ListView.builder( controller: _controller, itemCount: brews.length, itemBuilder: (context, index) { return BrewTile(brew: brews[index]); }, ), ); } } Future<List<Brew>> get brewss async { QuerySnapshot snapshot = await brewsCollection .orderBy('timestamp', descending: true) .limit(2) .getDocuments(); return _postListFromSnapshot(snapshot); }
-
Sandeep Sharma about 4 yearsIn first you want to fetch 10 items only?
-
alex about 4 yearsit could be 20..but then i want to load more on scroll..
-
pskink about 4 years
-
alex about 4 yearsthank you very much..but could you possibly simplify it a bit..i'm just a beginner here and this looks a bit complex.. @pskink
-
pskink about 4 yearsyou have a complete working widget, just use it
-
wcyankees424 about 4 yearshey alex, I see you are still struggling with this I will have an answer for you in a little while
-
alex about 4 yearsHey Jim..its been a while.. hope you're alright..@wcyankees424
-
-
alex about 4 yearsFuture<List<Brew>> get brews async { QuerySnapshot snapshot = await brewsCollection .orderBy('timestamp', descending: true).getDocuments(); return _brewListFromSnapshot(snapshot); }
-
alex about 4 yearsthis is how i get my current list..i've added the scrollController ..is it possible for you to show me the function i need to add here?
-
Chad Lamb about 4 yearsYou mean how to get 10 items from firestore at a time?
-
alex about 4 yearsInitially with the code above..it loads all the brews in the list..but i want to load only 10 brews initially and then when the user reaches the end of the list of initially loaded 10 brews..I want to load 10 more and so on ..
-
Chad Lamb about 4 yearsThat has to do with how you can paginate the data which is stored in firestore using some kind of query. I see that you have asked about this before and received a reasonable answer. stackoverflow.com/a/61133438/5211220 Basically you need to be able to write your queries to get documents in chunks of 10. If you have an auto incrementing integer property on the documents you can order by that, then initially select where that property is between 0 and 11 initially. Then on the second query between 10 and 21 etc.
-
alex about 4 yearsI tried it but thats not working anymore..because i'm ordering the items according to the timestamp as i wrote in the above comment..it'd be highly appreciated if you can edit the above code and make the necessary changes..
-
Chad Lamb about 4 yearsThe principle is the same. Query the first 10 items similar to how @Sandeep showed, ordering by the timestamp. Take the last timestamp and query the next 10 items using that timestamp as part of a where clause and a limit. I have not used the firestore api, but a quick google and I came up with something like the following.
Dart Firestore.instance.collection('brew').document(items) .where('timeStamp' isLessThan: previousTimestamp).orderBy('timeStamp', descending:true).limit(10);
-
alex about 4 yearsThis doesn't answer my question but thank you for making the effort..i'm trying to find out how to order the next set of data which startsAfter() the last set of data that is initially loaded on the screen.
-
Tyler Biscoe about 4 years@alex I see. I edited my answer to include the code that actually queries firestore. I think you might need
startAftrerDocument
. Side note: I feel your pain. The docs for firebase in dart/flutter are not great. Good luck! -
Tyler Biscoe about 4 yearsIf my edit does the trick, I'll return later and make my response more concisely answer your question.
-
alex about 4 yearsyes i need the startAfterDocument let me try and see if this works out..but it was helpful so i'll give an upvote to this..