Package selection guidance compiled from public package information, community data, and project usage.
HugeListView is a high-performance scrolling widget designed to handle lists with an extremely large number of items efficiently. It optimizes rendering by only building visible widgets, reducing memory usage and improving responsiveness. Ideal for applications requiring smooth scrolling through thousands or millions of entries, such as long message threads, data grids, or extensive catalogs. Built with Flutter's lazy loading principles, it ensures minimal overhead even with massive datasets. The package supports all major platforms including Android, iOS, Web, macOS, Windows, and Linux.
Use cases
Displaying large datasets in apps
Creating scrollable lists with millions of items
Building efficient data grids
Implementing infinite scroll interfaces
Optimizing performance for long message threads
Key features
Efficient rendering of massive lists
Lazy loading of visible items only
Low memory footprint
Cross-platform compatibility
Smooth scrolling experience
Supports custom item builders
Suitable for
Developers needing high-performance lists
Apps with extensive data sets
Scalable UI components
Performance-critical applications
Web and mobile apps with large content
Considerations
May require careful state management
Not ideal for small lists
Customization may need additional code
Limited documentation compared to core widgets
Potential complexity when integrating with other scroll controllers
Original README
Original README snapshot from the linked source repository. Visit the repository for the latest content.
Huge ListView
A performant ListView that can handle any number of items with ease. Unlike other infinite list approaches,
it doesn't just add new items to the list, growing to huge sizes in the end, but has a fixed size cache that
only keeps a handful of pages (in other words, a few hundred items at most) all the time, discarding old pages
as new ones come in. The list asks for a pageful of items at once, in an async function, expecting to receive
a Future<List<T>> of your items.
This approach means that the actual number of items in the list makes no difference. Hundreds of thousands or
even millions of items are all the same. You never have to read and keep all of them in memory at the same time.
Instead of a regular ListView, it uses a ScrollablePositionedList inside that makes it possible to scroll
to specific items rather than scroll positions. The items don't have to be of uniform height, their size differences
don't affect performance at all. This list implementation, however, doesn't play nice with the regular Scrollbar,
so we use our own DraggableScrollbar instead. This way we can support both a scrollbar and the usual position-based
scrolling as well.
staticconstint PAGE_SIZE = 12;
final listKey = GlobalKey<HugeListViewState>();
final scroll = ItemScrollController();
final controller = HugeListViewController(totalItemCount: 999999);
HugeListView<MyDataItem>(
/// Only needed if you expect to make use of its [setPosition] function.
key: listKey,
/// Only needed if you expect to make use of its [jumpTo] or [scrollTo] functions (the thumb expects it, though).
scrollController: scroll,
/// Only needed if you expect to provide the total count of items.
listViewController: controller,
/// Size of the page. [HugeListView] only keeps a few pages of items in memory any time.
pageSize: PAGE_SIZE,
/// Index of an item to initially align within the viewport.
startIndex: 0,
/// Called to load items for the list with the specified [pageIndex].
pageFuture: (page) => _loadPage(page, PAGE_SIZE),
/// Called to build an individual item with the specified [index].
itemBuilder: (context, index, MyDataItem entry) {
returnText(entry.name);
},
/// Called to build the thumb. One of [DraggableScrollbarThumbs.RoundedRectThumb], [DraggableScrollbarThumbs.ArrowThumb],/// [DraggableScrollbarThumbs.SemicircleThumb] or build your own.
thumbBuilder: DraggableScrollbarThumbs.SemicircleThumb,
/// Background color of scroll thumb, defaults to white.
thumbBackgroundColor: Colors.white,
/// Drawing color of scroll thumb, defaults to gray.
thumbDrawColor: Colors.grey,
/// Height of scroll thumb, defaults to 48.
thumbHeight: 48,
/// Called to build a placeholder while the item is not yet availabe.
placeholderBuilder: (context, index) => <some Widget>,
/// Called to build a progress widget while the whole list is initialized.
waitBuilder: (context) => <some Widget>,
/// Called to build a widget when the list is empty.
emptyBuilder: (context) => <some Widget>,
/// Called to build a widget when there is an error.
errorBuilder: (context, error) => <some Widget>,
/// Event to call with the index of the topmost visible item in the viewport while scrolling./// Can be used eg. to display the current letter of an alphabetically sorted list.
firstShown: (index) {},
/// The axis along which the list view scrolls. Defaults to [Axis.vertical].
scrollDirection: Axis.vertical,
/// The amount of space by which to inset the list.
padding: EdgeInsets.all(6.0),
/// Whether the scroll thumb slides out when not used, defaults to always visible.
alwaysVisibleThumb: false,
/// How quickly the scroll thumb animates in and out. Ignored if `alwaysVisibleThumb` is true./// Defaults to kThemeAnimationDuration.
thumbAnimationDuration = constDuration(milliseconds: 300),
/// How long the scroll thumb stays visible before disappearing. Ignored if `alwaysVisibleThumb` is true./// Defaults to 1 second.
thumbVisibleDuration = constDuration(milliseconds: 600),
/// Optional external LruMap to be used for cache.finalLruMap<int, HugeListViewPageResult<T>>? lruMap;
);
You have to pass a list of your items to pageFuture, for instance, given a list named data:
Future<List<MyDataItem>> _loadPage(int page, int pageSize) async {
int from = page * pageSize;
int to = min(data.length, from + pageSize);
return data.sublist(from, to);
}
The waitBuilder can be a simple centered CircularProgressIndicator but a nicer idea is
to provide a placeholderBuilder that is a mockup of the data to arrive. Many apps and sites
use gray horizontal bars instead of the actual text during loading. As an example,
here is a simple function that creates such a bar with randomly varying length: