Open In App

Flutter – Implementing Pull to Refresh

Last Updated : 09 Apr, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

The pull-to-refresh or (swipe-to-refresh) feature enables a user to pull down to fetch more data. The pull-to-refresh feature can be seen in many modern apps. The pull-to-refresh feature can be implemented in those components that are scrollable.

In this article, we are going to implement this feature in Flutter. Flutter is all about widgets; everything in Flutter is nothing but widgets and also it provides a widget to implement this feature as well as i.e. , RefreshIndicator.

RefreshIndicator: When the child’s Scrollable descendant overscrolls, an animated circular progress indicator is faded into view. When the scroll ends, if the indicator has been dragged far enough for it to become completely opaque, the onRefresh callback is called. The callback is expected to update the scrollable’s contents and then complete the Future it returns. The refresh indicator disappears after the callback’s Future has completed.

To create a flutter application, open the terminal/ command and run the below command:

flutter create app_name
// app_name should be the name of your app

To know more about it refer this article: Creating a Simple Application in Flutter.

After running this command, you should have a folder with the specified app_name. Navigate into that folder and open lib/main.dart file.

Note: In order to implement pull-to-refresh feature we are not going to use any other dependencies.

To create a RefreshIndicator, use the below syntax:

RefreshIndicator(
child: ...
onRefresh: ...
)

These are required fields.

  • child: Should be a scrollable widget
  • onRefresh: A function that should return a future.


Step-by-Step Implementation

Step 1 : Prepare Some Sample Data

As discussed above, for RefreshIndicator to wor,k we are going to need a scrollable component. So, for that, we are going to use ListView. In this step, we are going to define some demo data for our app.

Dart
// Local State to display items in listview
List<String> _demoData;

// This method will run once widget is loaded
// i.e when widget is mounting
@override
void initState() {
    
    // initializing state / demo data
    _demoData = [
        "Flutter",
        "React Native",
        "Cordova/ PhoneGap",
        "Native Script"
    ];
    super.initState();
}


Step 2 : Build a ListView

We are going to create our ListView with ListItem and AlwaysScrollingPhysics.

Dart
//... some code

ListView.builder(
    itemBuilder: (ctx, idx) {
        
        // List Item
        return Card(
            child: ListTile(
                        title: Text(_demoData[idx]),
                  ),
        );
    },
    
    // Length of the list
    itemCount: _demoData.length,
    
    // To make listView scrollable
    // even if there is only a single item.
    physics: const AlwaysScrollableScrollPhysics(),
)
  
//... some code


Step 3 : Wrap with RefreshIndicator

Finally, wrap ListView into RefreshIndicator to use the pull-to-refresh feature.

Dart
// ... some code

RefreshIndicator(
  child: ListView.builder(
    itemBuilder: (ctx, idx) {
      
      // List Item
      return Card(
        child: ListTile(
          title: Text(_demoData[idx]),
        ),
      );
    },

    // Length of the list
    itemCount: _demoData.length,

    // To make listView scrollable
    // even if there is only a single item.
    physics: const AlwaysScrollableScrollPhysics(),
  ),
  
  // Function that will be called when
  // user pulls the ListView downward
  onRefresh: () {
    return Future.delayed(
      Duration(seconds: 1),
      () {
        
        /// adding elements in list after [1 seconds] delay
        /// to mimic network call
        ///
        /// Remember: setState is necessary so that
        /// build method will run again otherwise
        /// list will not show all elements
        setState(() {
          _demoData.addAll(["Ionic", "Xamarin"]);
        });
        
        // showing snackbar
        ScaffoldMessenger.of(context).showSnackBar(
			SnackBar(
				content: const Text('Page Refreshed'),
			),
		);
      },
    );
  },
)
  
// ... some code


Complete Source Code

main.dart:

Dart
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
        return MaterialApp(
            title: 'GeeksforGeeks',
            
            // to hide debug banner
            debugShowCheckedModeBanner: false,
            theme: ThemeData(primarySwatch: Colors.green),
            home: HomePage(),
        );
    }
}

/// [StatefulWidget] so that we can change
/// internal state to show proper working
/// of [PULL TO REFRESH] feature
class HomePage extends StatefulWidget {
    @override
    _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
    
    // ScaffoldKey object. This is required
    // to show snackbar
    // This is optional. This is not required always
    late GlobalKey<ScaffoldState> _scaffoldKey;
    
    // Local State to display items in listview
    late List<String> _demoData;
    
    // This method will run once widget is loaded
    // i.e when widget is mounting
    @override
    void initState() {
        
        // initializing states
        _demoData = [
            "Flutter",
            "React Native",
            "Cordova/ PhoneGap",
            "Native Script",
        ];
        _scaffoldKey = GlobalKey();
        super.initState();
    }
    
    // This method will run when widget is unmounting
    @override
    void dispose() {
        
        // disposing states
        _scaffoldKey?.currentState?.dispose();
        super.dispose();
    }
    
    @override
    Widget build(BuildContext context) {
        return SafeArea(
            child: Scaffold(
                key: _scaffoldKey,
                appBar: AppBar(
                    title: const Text('GeeksforGeeks'),
                    backgroundColor: Colors.green,
                    foregroundColor: Colors.white,
                ),
                
                // Widget to show RefreshIndicator
                body: RefreshIndicator(
                    child: ListView.builder(
                        itemBuilder: (ctx, idx) {
                            
                            // List Item
                            return Card(child: ListTile(title: Text(_demoData[idx])));
                        },
                        
                        // Length of the list
                        itemCount: _demoData.length,
                        
                        // To make listView scrollable
                        // even if there is only a single item.
                        physics: const AlwaysScrollableScrollPhysics(),
                    ),
                    
                    // Function that will be called when
                    // user pulls the ListView downward
                    onRefresh: () {
                        return Future.delayed(Duration(seconds: 1), () {
                        
                        /// adding elements in list after [1 seconds] delay
                        /// to mimic network call
                        ///
                        /// Remember: [setState] is necessary so that
                        /// build method will run again otherwise
                        /// list will not show all elements
                        setState(() {
                            _demoData.addAll(["Ionic", "Xamarin"]);
                        });
                        
                        // showing snackbar
                        ScaffoldMessenger.of(context).showSnackBar(
                                SnackBar(content: const Text('Page Refreshed')
                                )
                            );
                          }
                        );
                    },
                ),
            ),
        );
    }
}

Note: In some cases, you will notice that the refresh indicator is not showing. To make it visible all the time please use physics: In Flutter all the scrollable widgets have physics properties.

The below will enable scrolling even if there are only a few elements in the list.

ListView(
physics: const AlwaysScrollableScrollPhysics(),
...
)


Output:




Next Article

Similar Reads