How to create your own pull to refresh / custom refresh indicator widget in Flutter.
TLDR; package, online example.
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 which (back then) was just a 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 — a type of work that almost always ends in some production f… problems. I have created custom_refresh_indicator_package (available on pub.dev).
The main target of this package was to provide all data needed for pull-to-refresh functionality implementation in an as simple way as possible.
Below you can see an example indicator created on top of this package — Och wait! and there is also an ONLINE EXAMPLE?!
Okey… now we know that someone, sometimes for some reason, might like to implement its own unique pull-to-refresh indicator.
But how?
Let’s imagine that we have a simple screen that looks like this:
and which is written like that:
To add pull-to-refresh functionality, we must wrap the list widget with the CustomRefreshIndicator widget that is provided by custom_refresh_indicator
package:
Let’s take a look at the changes.
Import
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.
onRefresh
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 effect after the pull to refresh gesture is made on your list.
child
We assigned our scrollable widget to the child argument — still the same way as we would like to do this with theRefreshIndicator
widget.
builder
The builder argument is 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
.
- BuildContext — It’s a quite common argument, so I think that I can skip it 😉.
- The child argument is basically the scrollable widget we assigned to the child widget argument (quite similar behavior to that known from the
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 😄. - 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. The controller extends theChangeNotifier
class, and thanks to that, we can listen to its changes.
I̶m̶p̶o̶r̶t̶a̶n̶t̶!̶ ̶
̶B̶u̶i̶l̶d̶e̶r̶ ̶f̶u̶n̶c̶t̶i̶o̶n̶ ̶w̶i̶l̶l̶ ̶n̶o̶t̶ ̶b̶e̶ ̶c̶a̶l̶l̶e̶d̶ ̶e̶v̶e̶r̶y̶ ̶c̶o̶n̶t̶r̶o̶l̶l̶e̶r̶ ̶d̶a̶t̶a̶ ̶c̶h̶a̶n̶g̶e̶ ̶s̶o̶ ̶t̶o̶ ̶a̶n̶i̶m̶a̶t̶e̶ ̶y̶o̶u̶r̶ ̶i̶n̶d̶i̶c̶a̶t̶o̶r̶ ̶w̶i̶d̶g̶e̶t̶ ̶y̶o̶u̶ ̶s̶h̶o̶u̶l̶d̶ ̶c̶o̶n̶s̶i̶d̶e̶r̶ ̶u̶s̶i̶n̶g̶ ̶A̶n̶i̶m̶a̶t̶e̶d̶B̶u̶i̶l̶d̶e̶r̶ ̶w̶i̶d̶g̶e̶t̶.̶
Hi, it’s me from the future 👋😅 As the custom_refresh_indicator 2.0.0 was released, this is no longer true. Since 2.0.0, the builder function rebuilds automatically. However! if your widget is complex and needs some optimization, it might still be a good choice to restore the old behavior and use AnimatedBuilder widget to decide which part of the widget tree to rebuild. To do so, simply set the autoRebuild
argument to false
— that was easy, right? 😄
So… the above example will provide a pull-to-refresh behavior — the user can drag the list to call the onRefresh
function — BUT — without visual effect because the builder
function always returns our list without any changes. Therefore, when talking about user experience…
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 a Stack
widget with some Transforms
in it, and that's the effect:
To better understand how controller data changes, let’s look at the example below.
In Summary
As you can see, to implement your custom refresh indicator widget, you do not need to copy dozens of lines of code that you do not even understand from other libraries to your project codebase. 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!