flutterdart

pull down to REFRESH in Flutter


My dashboard code looks like this, Here I am doing get req in getReport method, I have added the RefreshIndicator in the code which when pulled down inside container should do the refresh, there I am calling my getData(), But I am not getting the refreshed content, I am adding my code below, let me know if anywhere I made a mistake.

below my dashboard.dart

class Window extends StatefulWidget {
  @override
  _WindowState createState() => _WindowState();
}

class _WindowState extends State<Window> {
  Future reportList;    
  @override
  void initState() {
    super.initState();
    reportList = getReport();
  }    

  Future<void> getReport() async {
    http.Response response =
        await http.get(reportsListURL, headers: {"token": "$token"});
    switch (response.statusCode) {
      case 200: 
        String reportList = response.body;
        var collection = json.decode(reportList);
        return collection;

      case 403:
          break;

      case 401:
        return null;

      default:
        return 1;
    }
  }

  getRefreshScaffold() {
    return Center(
      child: RaisedButton(
        onPressed: () {
          setState(() {
            reportList = getReport();
          });
        },
        child: Text('Refresh, Network issues.'),
      ),
    );
  }

  getDashBody(var data) {
    double maxHeight = MediaQuery.of(context).size.height;
    return Column(
      children: <Widget>[
        Container(
          height: maxHeight - 800,
        ),
        Container(
          margin: new EdgeInsets.all(0.0),
          height: maxHeight - 188,
          child: new Center(
          child: new RefreshIndicator(          //here I am adding the RefreshIndicator
          onRefresh:getReport,                  //and calling the getReport() which hits the get api
          child: createList(context, data),
          ),),
        ),
      ],
    );
  }

  Widget createList(BuildContext context, var data) {
    Widget _listView = ListView.builder(
      itemCount: data.length,
      itemBuilder: (context, count) {
        return createData(context, count, data);
      },
    );
    return _listView;
  }

  createData(BuildContext context, int count, var data) {
    var metrics = data["statistic_cards"].map<Widget>((cardInfo) {
      var cardColor = getColorFromHexString(cardInfo["color"]);
      if (cardInfo["progress_bar"] != null && cardInfo["progress_bar"]) {
        return buildRadialProgressBar(
          context: context,
          progressPercent: cardInfo["percentage"],
          color: cardColor,
          count: cardInfo["value"],
          title: cardInfo["title"],
        );
      } else {
        return buildSubscriberTile(context, cardInfo, cardColor);
      }
    }).toList();

    var rowMetrics = new List<Widget>();
    for (int i = 0; i < metrics.length; i += 2) {
      if (i + 2 < metrics.length)
        rowMetrics.add(Row(children: metrics.sublist(i, i + 2)));
      else
        rowMetrics.add(Row(children: [metrics[metrics.length - 1], Spacer()]));
    }
    return SingleChildScrollView(
      child: LimitedBox(
        //  maxHeight: MediaQuery.of(context).size.height / 1.30,
        child: Column(
          mainAxisSize: MainAxisSize.max,
          mainAxisAlignment: MainAxisAlignment.center,
          children: rowMetrics,
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: reportList,
      builder: (BuildContext context, AsyncSnapshot snapshot) {
        switch (snapshot.connectionState) {
          case ConnectionState.none:
          case ConnectionState.waiting:
          case ConnectionState.active:
            return Center(
              child: CircularProgressIndicator(),
            );
          case ConnectionState.done:
            var data = snapshot.data;
            if (snapshot.hasData && !snapshot.hasError) {
              return getDashBody(data);
            } else if (data == null) {
              return Center(
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: <Widget>[
                    Text("Timeout! Log back in to continue"),
                    Padding(
                      padding: EdgeInsets.all(25.0),
                    ),
                    RaisedButton(
                      onPressed: () {
                        setState(() {
                          token = null;
                        });
                        Navigator.of(context).pushReplacement(
                          CupertinoPageRoute(
                              builder: (BuildContext context) => LoginPage()),
                        );
                      },
                      child: Text('Login Again!'),
                    ),
                  ],
                ),
              );
            } else {
              getRefreshScaffold();
            }
        }
      },
    );
  }
}

Solution

  • Basic RefreshIndicator Example

    Below is a State class of a StatefulWidget, where:

    import 'package:flutter/material.dart';
    import 'dart:math';
    
    class PullRefreshPage extends StatefulWidget {
      const PullRefreshPage();
    
      @override
      State<PullRefreshPage> createState() => _PullRefreshPageState();
    }
    
    class _PullRefreshPageState extends State<PullRefreshPage> {
      List<String> numbersList = NumberGenerator().numbers;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: RefreshIndicator(
            onRefresh: _pullRefresh,
            child: ListView.builder(
              itemCount: numbersList.length,
              itemBuilder: (context, index) {
                return ListTile(
                  title: Text(numbersList[index]),
                );
              },),
          ),
        );
      }
    
      Future<void> _pullRefresh() async {
        List<String> freshNumbers = await NumberGenerator().slowNumbers();
        setState(() {
          numbersList = freshNumbers;
        });
        // why use freshNumbers var? https://stackoverflow.com/a/52992836/2301224
      }
    }
    
    class NumberGenerator {
      Future<List<String>> slowNumbers() async {
        return Future.delayed(const Duration(milliseconds: 1000), () => numbers,);
      }
    
      List<String> get numbers => List.generate(5, (index) => number);
    
    
      String get number => Random().nextInt(99999).toString();
    }
    

    Notes


    FutureBuilder with RefreshIndicator Example

    Here's another version of the above State<PullRefreshPage> class using a FutureBuilder, which is common when fetching data from a Database or HTTP source:

    class _PullRefreshPageState extends State<PullRefreshPage> {
      late Future<List<String>> futureNumbersList;
    
      @override
      void initState() {
        super.initState();
        futureNumbersList = NumberGenerator().slowNumbers();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: FutureBuilder<List<String>>(
            future: futureNumbersList,
            builder: (context, snapshot) {
              return RefreshIndicator(
                child: _listView(snapshot),
                onRefresh: _pullRefresh,
              );
            },
          ),
        );
      }
    
      Widget _listView(AsyncSnapshot snapshot) {
        if (snapshot.hasData) {
          return ListView.builder(
            itemCount: snapshot.data.length,
            itemBuilder: (context, index) {
              return ListTile(
                title: Text(snapshot.data[index]),
              );
            },);
        }
        else {
          return Center(
            child: Text('Loading data...'),
          );
        }
      }
    
      Future<void> _pullRefresh() async {
        List<String> freshNumbers = await NumberGenerator().slowNumbers();
        setState(() {
          futureNumbersList = Future.value(freshNumbers);
        });
      }
    }
    

    Notes