Flutter — How to make your ScrollView support pull-to-refresh?
RefreshIndicator comes to help!

It’s an useful behavior on the mobile app that when we scroll to the top of a vertical scroll view, and overscroll, a refresh indicator will drop down, then the new data updates after we release the control. Flutter provides a handy widget called RefreshIndicator
for this purpose.
As the official documentation says, RefreshIndicator
is a widget that supports the Material “swipe to refresh” idiom. Today, we’re going to learn how to implement it in our ScrollView.
Table of Contents
- Implement
RefreshIndicator
inListView
. - Implement
RefreshIndicator
inCustomScrollView
. - Cupertino style of refresh indicator in iOS.
- Known issues with
WebView
.
Implement RefreshIndicator
in ListView
Let’s try to display 100 random numbers which are generated from Random().nextInt()
at the beginning. After pulling to refresh, a new list of random numbers will be regenerated and display on the screen.
Follow the steps to achieve it:
- Wrap your
ListView
intoRefreshIndicator
like L36 does. - Provide a future task to the parameter
onRefresh
in L37. The purpose of the future task is to fetch the new data, then refresh the widget.

Implement RefreshIndicator
in CustomScrollView
RefreshIndicator
can also be used for CustomScrollView
. As the following code, we create a CustomScrollView
with a SliverList and a SliverGrid. You can refer to my previous post for the CustomScrollView details.
The main function is in L36 to L44, we wrap a CustomScrollView
into a RefreshIndicator
. Then we can achieve the purpose of pulling to refresh the whole ScrollView. It is quite easy, right?

Parameters
There are also some parameters we can use to change the UI.
- displacement
The distance from the child’s top or bottom edge to where the refresh indicator will settle.
RefreshIndicator(
onRefresh: _refreshRandomNumbers,
displacement: 200.0,
child: ListView.builder(...),
);

- color/background color, stroke width of the indicator:
RefreshIndicator(
onRefresh: _refreshRandomNumbers,
color: Colors.blue,
backgroundColor: Colors.red,
strokeWidth: 10.0,
child: ListView.builder(...),
);

Cupertino style of refresh indicator in iOS
We can also change the style of refresh indicator to Cupertino style. CupertinoSliverRefreshControl
is an iOS equivalent of the pull-to-refresh pattern. Here is the documentation:
Must be used as a sliver inside a [CustomScrollView] instead of wrapping around a [ScrollView] because it's a part of the scrollable instead of being overlaid on top of it.
According to it, the implementation will be like:
in L39, we wrap CupertinoSliverRefreshControl
into a CustomScrollView
. Actually, CupertinoSliverRefreshControl
is a sliver widget implementing the iOS-style pull-to-refresh content control. That’s why we need to put it in the CustomScrollView
. Here is what it looks like on iOS:

Everything works like a charm on iOS, however, it doesn’t work on Android directly.
Please checkout the reason and solution here:
https://github.com/flutter/flutter/issues/27977#issuecomment-464175636
This is working as intended. It’s due to the
ScrollPhysics
which is used on Android. iOS usesBouncingScrollPhysics
which doesn't apply any boundary conditions whenapplyBoundaryConditions
is called i.e. it allows for under/overscrolling. If you want the same effect on Android you can useBouncingScrollPhysics
which will give you the an iOS feel on Android, or you can overrideClampingScrollPhysics
which is what Android uses.
So we can fix it by using BouncingScrollPhysics
for CustomScrollView
.
@override
Widget build(BuildContext context) => CustomScrollView(
physics: const BouncingScrollPhysics(),
slivers: [
CupertinoSliverRefreshControl(
onRefresh: _refreshRandomNumbers,
),
_sliverListView,
_sliverGridView,
],
);
Issues
I’ve tried to implement pull-to-refresh function on the WebView, however, it didn’t seem to work. Then I found an issue on the Flutter Github about this.
https://github.com/flutter/flutter/issues/71341
RefreshIndicator
or similar functionality isn’t compatible withwebview_flutter
.
Unfortunately, we need to wait for the Flutter team to solve it.
That’s all for today. Thank you for reading this article. Hope it helps you to learn more about how the implement RefreshIndicator in all your ScrollView. If you have any suggestions or questions, welcome to leave a comment below. See you next time 🙌.
References
- RefreshIndicator official documentation:
- An article about the details of implementing pull-to-refresh behavior:
https://www.woolha.com/tutorials/flutter-pull-to-refresh-using-refreshindicator-and-cupertinosliverrefreshcontrol