I would like to have a ListView in flutter which provides lazy loading in both directions (up, down).
Example:
- There are 60000 items in the backend database which can be theoretically displayed.
- First I want to display the items 100..120
- From these indices I want to be able to scroll up and down while lazy loading the new items
Things to consider:
- The top and bottom edge (current index < 0 or > 60000) should be bouncing if reached while scrolling
What I've tried:
- Most of the approaches in Flutter ListView lazy loading. These solutions just worked for lazy loading in one direction (e.g. down or up if list is reversed). If scrolling into the other direction, the list view "jumped" because indices changed (the old index 1 isn't the new index 1 anymore).
- ScrollablePositionedList (https://pub.dev/documentation/flutter_widgets/latest/flutter_widgets/ScrollablePositionedList-class.html): Here the issue was that the widget wants to load every item if e.g. an itemcount of 60000 is given. Anyhow, the itemcount is required in order that this solution works properly.
- IndexedListView (https://pub.dev/packages/indexed_list_view): Same issue as in ScrollablePositionedList. Anyhow, here also the "bouncing" at the top and bottom of the list didn't work (because of missing scroll extents).
- InfiniteListView (https://github.com/fluttercommunity/flutter_infinite_listview): Same issue as in IndexedListView
I hope that here are some pretty smart people who can help me solving this issue ;). I'm already searching and trying around since days on this issue. Thanks!
Update To make things clearer: Here is an example for a ListView with lazy loading for scrolling up and down (Most of the code copied from https://stackoverflow.com/a/49509349/10905712 by Rémi Rousselet):
import 'dart:math';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class MyHome extends StatefulWidget {
@override
_MyHomeState createState() => new _MyHomeState();
}
class _MyHomeState extends State<MyHome> {
ScrollController controller;
List<String> items = new List.generate(100, (index) => 'Hello $index');
@override
void initState() {
super.initState();
controller = new ScrollController()..addListener(_scrollListener);
}
@override
void dispose() {
controller.removeListener(_scrollListener);
super.dispose();
}
@override
Widget build(BuildContext context) {
return new Scaffold(
body: new Scrollbar(
child: new ListView.builder(
controller: controller,
itemBuilder: (context, index) {
return new Text(items[index]);
},
itemCount: items.length,
),
),
);
}
double oldScrollPosition = 0.0;
void _scrollListener() {
bool scrollingDown = oldScrollPosition < controller.position.pixels;
print(controller.position.extentAfter);
if (controller.position.extentAfter < 500 && scrollingDown) {
setState(() {
items.addAll(new List.generate(
42, (int index) => Random().nextInt(10000).toString()));
});
} else if (controller.position.extentBefore < 500 && !scrollingDown) {
setState(() {
items.insertAll(
0,
new List.generate(
42, (index) => Random().nextInt(10000).toString()));
});
}
oldScrollPosition = controller.position.pixels;
}
}
If you execute this code and try scrolling up, you'll see a "jumping" in the list. Scrolling down + lazy load works perfectly. Scrolling up + lazy load would work if the ListView would be reversed. Anyhow, with this solution we would have the same issue with scrolling down + lazy load here.
Update
I just created a new library bidirectional_listview which can be used to solve this issue. BidirectionalListView is a fork from infinite_listview.
Old Answer
I just solved it by adapting the library InfiniteListView a bit. I had to extend a setter for minScrollExtent and maxScrollExtent. In addition, I added a separate count for negative indices:
The following example demonstrates lazy loading with scroll boundaries in both directions, up and down: