In this tutorial, we’ll build a simple Flutter app that fetches a to-do list from an open API and displays it on the screen. We also implement a Pull-to-Refresh feature that lets the user refresh the content by making a pulling-down gesture.
Here’s the API endpoint used in the app (thanks to the Typicode team):
https://jsonplaceholder.typicode.com/todos
It simply contains a list of todos (tasks). A single todo looks like this:
{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
}
Table of Contents
The Example
Preview
Here’s how the sample app we are going to build works:
Note: To implement Pull-to-Refresh, what we have to do is just wrap our widgets with a RefreshIndicator widget and configure the onRefresh property.
The Steps
1. Project setup
Create a new Flutter project by running this command:
flutter create app_example
2. Installing the HTTP package to fetch data from APIs.
Run the following command to programmatically add the latest version of package HTTP to the dependencies section of your pubspec.yaml file:
flutter pub add http
Then execute:
flutter pub get
3. The final code
The complete code in main.dart (with explanations):
// main.dart
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
// Hide the debug banner
debugShowCheckedModeBanner: false,
title: 'Kindacode.com',
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
// The initial todos
List _todos = [];
// Call this when the user pull down the screen
Future<void> _loadData() async {
const url = 'https://jsonplaceholder.typicode.com/todos';
try {
final http.Response response = await http.get(Uri.parse(url));
final _loadedTodos = json.decode(response.body);
setState(() {
_todos = _loadedTodos;
});
} catch (err) {
rethrow;
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Kindacode.com'),
),
body: RefreshIndicator(
// trigger the _loadData function when the user pulls down
onRefresh: _loadData,
// Render the todos
child: ListView.builder(
itemCount: _todos.length,
itemBuilder: (BuildContext ctx, index) {
return Card(
margin:
const EdgeInsets.symmetric(horizontal: 15, vertical: 8),
child: ListTile(
// Render each todo
leading: Text(_todos[index]['id'].toString()),
title: Text(_todos[index]["title"]),
trailing: _todos[index]["completed"]
? const Icon(
Icons.check_circle,
color: Colors.blue,
)
: const Icon(
Icons.circle,
color: Colors.yellow,
),
),
);
})),
);
}
}
If you want to load data when the app starts, see this article: Flutter FutureBuilder example (null safety).
Conclusion
We have walked through an end-to-end example of implementing Pull-to-Refresh in a Flutter application with RefreshIndicator. If you would like to explore more interesting things about Flutter, take a look at the following articles:
- Load and display content from CSV files
- Best Libraries for Making HTTP Requests in Flutter
- Flutter & Hive Database: CRUD Example
- Set an image Background for the entire screen
- 3 Ways to create Random Colors in Flutter
- Flutter Cupertino Button – Tutorial and Examples
You can also check out our Flutter topic page or Dart topic page for the latest tutorials and examples.