Flutter RefreshIndicator Widget
Source: Nagaraj Alagusundaram
Introduction:
Pull to refresh is an essential and simple feature for a dynamic list in a mobile app. In recent years the usage of this widget has dramatically increased even before the launch of the Flutter itself.
In this blog, we’ll see how to implement the pull to refresh feature in Android & iOS using Flutter. We aim to have a native look and feel for the pull-to-refresh app using the same codebase.
As per the documentation, RefreshIndicator class is a widget that supports the Material “swipe to refresh” idiom.
Here we will create an app that will add new data to the list on the pull-to-refresh event.
Result
Before we get into the actual code, first, let’s see the output.
In this example, we are refreshing a list view, which has a list of integers. And on each refresh, we’re adding ten more new rows.
Code
In the initState we’re creating a new list.
void initState() {
_intList = List.generate(10, (index) => index + 1).reversed.toList();
super.initState();
}
Code for RefreshIndicator
RefreshIndicator(
onRefresh: _refresh,
triggerMode: RefreshIndicatorTriggerMode.onEdge,
backgroundColor: Colors.blue,
color: Colors.white,
child: ListView.builder(
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics()),
itemCount: _intList.length,
itemBuilder: (context, index) {
return Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(_intList[index].toString()),
));
},
),
),
Here the background color of the RefreshIndicator is Colors.blue
, the progress bar indicator color is Colors.white
and finally, the logic for the onRefresh method defined in _refresh
Future<void> _refresh() {
return _getNewList().then((value) => setState(() {
_intList = value;
}));
}
Future<List<int>> _getNewList() async {
await Future.delayed(const Duration(seconds: 1));
var _newList = List.generate(_intList.length + 10, (index) => index + 1)
.reversed
.toList();
return _newList;
}
The full code
import 'dart:ui';
import 'package:flutter/material.dart';
List<int> _intList = [];
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'RefreshIndicator'),
scrollBehavior: MyCustomScrollBehavior(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
void initState() {
_intList = List.generate(10, (index) => index + 1).reversed.toList();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: RefreshIndicator(
// functional changes
onRefresh: _refresh,
triggerMode: RefreshIndicatorTriggerMode.onEdge,
// Visual changes
backgroundColor: Colors.blue,
color: Colors.white,
// actual list
child: ListView.builder(
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics()),
itemCount: _intList.length,
itemBuilder: (context, index) {
return Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(_intList[index].toString()),
));
},
),
),
),
);
}
Future<void> _refresh() {
return _getNewList().then((value) => setState(() {
_intList = value;
}));
}
Future<List<int>> _getNewList() async {
await Future.delayed(const Duration(seconds: 1));
var _newList = List.generate(_intList.length + 10, (index) => index + 1)
.reversed
.toList();
return _newList;
}
}
class MyCustomScrollBehavior extends MaterialScrollBehavior {
// Override behavior methods and getters like dragDevices
@override
Set<PointerDeviceKind> get dragDevices => {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
};
}