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(); } } }, ); } }
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.
Below is a State class of a StatefulWidget, where:
ListView
is wrapped in a RefreshIndicator
words
state variable is its data sourceonRefresh
calls _pullRefresh
function to update ListView _pullRefresh
is an async function, returning nothing (a Future<void>
)_pullRefresh
's long running data request completes, words
member/state variable is updated in a setState()
call to rebuild ListView
to display new dataimport '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(); } }
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. 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); }); } }
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
setState()
(futureWords
in FutureBuilder example & words
in Basic example), after its long running async data fetch functions have completed. async
, you'll get an exceptionsetState
and having an empty setState
closure, may result in hand-slapping / code analysis warnings in the futureNot 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;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With