Flutter: Lazy Loading on Scroll Made Simple

Yiran Hu
4 min readJan 7, 2020

--

(GitHub repo linked at the end of the article.)

A lot of times, you’ll need to load a long list of items from the web. In such cases, you wouldn’t want to load the entire list at once. Most likely, you would need to use GET to fetch the content lazily, that is, one page at a time. Also, you don’t need to get more until the user scrolls towards the bottom of the list. Yeah, something like this:

We will make this app that loads list contents lazily.

When I was developing my last app, I was in such a position, and looked everywhere for a simple solution. However, all the solutions I found involves some sort of advanced state management tools like the NotificationListener or ScrollController. By far the simplest solutions I found are AbdulRahman AlHamali’s FutureBuilder solution and a package called lazy_load_scrollview.

I wasn’t satisfied. My app was very simple and I intended to keep it that way. Isn’t there a simpler way to do this, using just the most basic StatefulWidget? I wondered… And the answer is no, you have to bear with it.

Just kidding… The answer is always yes, and I’m about to show you how.

The basic idea is to utilize the lazy loading behavior of the amazing ListView.builder(), and trigger the asynchronous fetching/loading when user hits the bottom, that is, when the builder calls the itemBuilder on the last item. In fact, the official Flutter Get Started App tutorial already uses the lazy loading mechanism to get an infinite list of word pairs. There are only two problems we have to deal with on top of that strategy:

  • The http GET is asynchronous and so are a lot of other loading actions.
  • (Optional) We need to stop loading when the list comes to and end.

Now let me walk you through step by step. We’ll start with an app that looks a lot like Get Started App from Flutter project: we have a StatefulWidget and its State that displays a list of word pairs. You may download the starting project or clone the tutorial repo and git checkout start.

Inside lib/list_screen.dart you’ll find a StatefulWidget and its State. Right now it simply displays a fixed list with a single item.

The starting point looks like this.

The _ItemFetcher class is here to act as a dummy http agent. Notice that its fetch() method is an async block that has a delayed future in it. The asynchronous behavior is the tricky element in our example: you need to make sure that it only gets called once for each page.

So what we gotta do now is to use the ListView.builder()’s itemBuilder callback. We deliberately set the itemCount to _pairList.length + 1 so that we can:

  • Display a loading indicator, and
  • Trigger fetch() when the list is near its bottom.

But be careful not to call fetch() when one is already underway, so we use a _isLoading flag to indicate if a fetch() is already triggered. The loading logic is implemented in the _loadMore() method. It first sets _isLoading to true and then fires off the fetch(). A then() block is used to deal with the future’s return.

In addition, we use a _hasMore flag to indicate that there’s no more items to fetch. When _hasMore is false we will set itemCount to _pairList.length so that the loading indicator won’t be shown anymore and no more fetch() would be triggered.

Putting these all together, the final code for the State looks like this:

Final product.

Voila, a simple solution that doesn’t go much further than the Get Started App, yet it satisfies everything we want! As you can see, this app doesn’t go far beyond the concepts of the Flutter getting started tutorial, avoiding some advanced concepts like the ScrollController or the FutureBuilder, and is suited for any beginner!

--

--