Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pull down to REFRESH in Flutter

Tags:

flutter

dart

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();             }         }       },     );   } } 
like image 548
mark Avatar asked Sep 17 '19 10:09

mark


People also ask

Which widgets in flutter helps you to refresh screen?

Flutter is all about widgets everything in flutter is nothing but widgets. Flutter also 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.


2 Answers

Basic Example

Below is a State class of a StatefulWidget, where:

  • a ListView is wrapped in a RefreshIndicator
    • words state variable is its data source
  • onRefresh calls _pullRefresh function to update ListView
    • _pullRefresh is an async function, returning nothing (a Future<void>)
    • when _pullRefresh's long running data request completes, words member/state variable is updated in a setState() call to rebuild ListView to display new data
import 'package:english_words/english_words.dart';  class _PullToRefreshPageState extends State<PullToRefreshPage> {   List<WordPair> words = generateWordPairs().take(5).toList();    @override   Widget build(BuildContext context) {     return RefreshIndicator(       onRefresh: _pullRefresh,       child: ListView.builder(         itemCount: words.length,         itemBuilder: (context, index) {           return ListTile(             title: Text(words[index].asPascalCase),           );         },),     );   }    Future<void> _pullRefresh() async {     List<WordPair> freshWords = await WordDataSource().getFutureWords(delay: 2);     setState(() {       words = freshWords;     });     // why use freshWords var? https://stackoverflow.com/a/52992836/2301224   } }  class WordDataSource {   Future<List<WordPair>> getFutureWords({int size = 5, int delay = 5}) async {     await Future.delayed(Duration(seconds: delay));     return generateWordPairs().take(5).toList();   } } 

Notes

  • If your async onRefresh function completes very quickly, you may want to add an await Future.delayed(Duration(seconds: 2)); after it, just so the UX is more pleasant.
  • This gives time for the user to complete a swipe / pull down gesture & for the refresh indicator to render / animate / spin indicating data has been fetched.

FutureBuilder Example

Here's another example, using a FutureBuilder, which is common when fetching data from a Database or HTTP source

class _PullToRefreshFuturePageState extends State<PullToRefreshPage> {   Future<List<WordPair>> futureWords;    @override   void initState() {     super.initState();     futureWords = WordDataSource().getFutureWords(delay: 2);   }    @override   Widget build(BuildContext context) {     return FutureBuilder<List<WordPair>>(       //initialData: [],       future: futureWords,       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].asPascalCase),           );         },);     }     else {       return Center(         child: Text('Loading data...'),       );     }   }    Future<void> _pullRefresh() async {     List<WordPair> freshFutureWords = await WordDataSource().getFutureWords(delay: 2);     setState(() {       futureWords = Future.value(freshFutureWords);     });   } } 

Notes

  • getFutureWords() function is the same as in the Basic Example above, but the data is wrapped in a Future.value() since FutureBuilder expects a Future
  • according to Rémi, Collin & other Dart/Flutter demigods it's good practice to update Stateful Widget member variables inside setState() (futureWords in FutureBuilder example & words in Basic example), after its long running async data fetch functions have completed.
    • https://stackoverflow.com/a/52992836/2301224
  • if you try to make setState async, you'll get an exception
  • updating member variables outside of setState and having an empty setState closure, may result in hand-slapping / code analysis warnings in the future
like image 195
Baker Avatar answered Sep 30 '22 22:09

Baker


Not sure about futures, but for refresh indicator you must return a void so Use something like

RefreshIndicator(                 onRefresh: () async  {                   await getData().then((lA) {                     if (lA is Future) {                       setState(() {                         reportList = lA;                       });                       return;                     } else {                       setState(() {                        //error                       });                       return;                     }                   });                    return;                 }, 

Try this and let me know!

EDIT:

Well, then just try this inside you refresh method

          setState(() {             reportList = getReport();             });           return reportList; 
like image 38
Cristian Bregant Avatar answered Oct 01 '22 00:10

Cristian Bregant