Image for post
Image for post

How to create your own pull to refresh / custom refresh indicator widget in Flutter.

Kamil Klyta
May 4 · 4 min read

A few months ago in a project that I was working on, there was a need to create a custom refresh indicator to replace the default indicator provided with a flutter material library. Back in those days, I found it really hard to find some simple solutions or packages that will provide basic functionality on which I will be able to implement it. The one and only thing that I was able to find was liquid_pull_to_refresh package that was just modification of the default material design refresh indicator widget, and I was like…

To avoid another: copy, paste, refactor and forgot why this file has over a thousand lines of code — type of work which almost always ends in some production f… problems. I have created custom_refresh_indicator_package (available on

The main target of this package was to provide all data needed for pull to refresh functionality implementation in as simple way as possible.

Below you can see an example indicator created on top of this package.

Example of the custom refresh indicator widget.
Example of the custom refresh indicator widget.
Example pull to refresh widget build on top of the custom_refresh_indicator package.

Okey… now we know that someone sometime for some reason might like to implement its own unique pull to refresh indicator.

Image for post
Image for post

But how?

Let’s imagine that we have a simple screen which looks like this:

Image for post
Image for post

and which is written like this:

To add pull to refresh functionality we must wrap the list widget with CustomRefreshIndicator widget that is provided by custom_refresh_indicator package:

Let’s take a look at changes.

First of all, we have added an import statement to the custom_refresh_indicator package, because we would like to build our indicator on top of it.

In the same way, as we are using RefreshIndicator widget we assigned a function that will return Future to the onRefresh argument. In the above example, we returned Future.delayed() as we do not want to take any action instead we just want to wait for a few seconds to simulate asynchronous function behavior, but basically this is the place when you are doing your API call or other asynchronous functions that will take an effect after the pull to refresh gesture is done on your list.

We assigned our scrollable widget into the child argument —still the same way as we would like to this with theRefreshIndicator widget.

The builder argument is something that its new in comparison to RefreshIndicator. This function will be used to build our pull to refresh widget. It takes three arguments in turn: the context of type BuildContext, child of type Widget and controller of type IndicatorController.

  1. BuildContext — It’s a quite common argument so I think that I can skip it 😉.
  2. The child argument is basically the scrollable widget that we assigned to the child widget argument (quite similar behavior to that known from AnimatedBuilder widget). So if we for some reason do not want to render our list we can skip the use of it — but it almost always makes no sense 😄.
  3. The third and most important argument is the controller of type IndicatorController. This argument contains all information about the scroll state that we would like to use to build our custom indicator. Controller extends ChangeNotifier class, thanks to this we can listen to its changes.

Builder function will not be called every controller data change so to animate your indicator widget you should consider using
AnimatedBuilder widget.

So… the above example will provide a pull to refresh behavior (user can drag the list to call onRefresh function but) without visual effect because the builder function always returns our list without any changes. So when talking about user experience…

Image for post
Image for post

But if for some reason we find that our users should suffer a little less, just a little 🤏. We would like to add some effect, so let’s do this!

As you can see we have added AnimatedBuilder widget that listens to changes notified by IndicatorController and Stack widget with some Transforms in it, and that's the effect:

Image for post
Image for post

To better understand how controller data changes let’s look at the below example.

Image for post
Image for post

In Summary

As you can see to implement your own custom refresh indicator widget you do not need to copy dozens of lines of code that you even do not understand from libraries of other people to your project code. Instead, add a custom refresh indicator package to your pubspec.yaml file and implement a few lines of builder function. That’s it, isn’t it simple 😏?

Do not wait! Create your own custom refresh indicator!

Flutter Community

Articles and Stories from the Flutter Community

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store