How to implement Pull-to-Refresh in Flutter

Updated: April 22, 2023 By: A Goodman Post a comment

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):

It simply contains a list of todos (tasks). A single todo looks like this:

    "userId": 1,
    "id": 1,
    "title": "delectus aut autem",
    "completed": false

The Example


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);

  Widget build(BuildContext context) {
    return const MaterialApp(
      // Hide the debug banner
      debugShowCheckedModeBanner: false,
      title: '',
      home: HomePage(),

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  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 = '';
    try {
      final http.Response response = await http.get(Uri.parse(url));
      final _loadedTodos = json.decode(response.body);
      setState(() {
        _todos = _loadedTodos;
    } catch (err) {

  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(''),
      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(
                      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(
                        : const Icon(
                            color: Colors.yellow,

If you want to load data when the app starts, see this article: Flutter FutureBuilder example (null safety).


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:

You can also check out our Flutter topic page or Dart topic page for the latest tutorials and examples.

Notify of
Inline Feedbacks
View all comments

Related Articles