Flutter allows asynchronous network requests via refreshIndicators and FutrueBuilder, as well as pull-down refresh and pull-up loading of data. Here to Zhihu Daily API as an example of demonstration, only for learning exchange.
instructions
In Flutter, asynchronous UI updates can be implemented through two components, FutureBuilder and StreamBuilder. For web requests, the combination of Futrue + FutureBuilder is usually used. For pull-down refresh, Flutter also provides a separate Widget called RefreshIndicator. This component has an onRefresh method that calls back asynchronous requests for data to enable pull-down refresh.
Const RefreshIndicator({Key Key, @required this.child, this.displacement = 40.0, @required this.onRefresh, this.color, this.backgroundColor, this.notificationPredicate = defaultScrollNotificationPredicate, this.semanticsLabel, this.semanticsValue, }) : assert(child ! = null), assert(onRefresh ! = null), assert(notificationPredicate ! = null), super(key: key);Copy the code
The ListView or ScrollController of another scrollable component is used to determine whether the scrolllist is rolled to the bottom. If so, the scrollUp function is called to obtain the data.
Effect:
implementation
First, network request
Here we take Zhihu Daily API as an example. The two apis are as follows
/// Update message const String LAST_NEWS ="https://news-at.zhihu.com/api/4/news/latest"; /// History messages const String HISTORY_NEWS ="https://news-at.zhihu.com/api/4/news/before/";
Copy the code
Network requests using Dio:
Response response = await dio.get(LAST_NEWS);
Copy the code
The data returned here is of Map type, so we can get the result we want directly according to the key. For example, get the date field in a message:
currentDate = response.data["date"].toString();
Copy the code
Second, FutureBuilder + ListView display data
FutureBuilder needs to be used in conjunction with a Future, first defining a Future and making asynchronous network requests.
///先定义一个 Future
Future getDataFuture;
...
@override
void initState() { super.initState(); getDataFuture = getItemNews(); Future<List<dynamic> > getItemNews() async{items.clear();print("Start getting updates.");
response = await dio.get(LAST_NEWS);
currentDate = response.data["date"].toString();
if(response.data["stories"] != null){
items.addAll(response.data["stories"]);
}
return items;
}
Copy the code
FutureBuilder + ListView displays the data
FutureBuilder<List<dynamic>>(/// specify Future Future: getDataFuture, Builder: (context,AsyncSnapshot<List<dynamic>> async){/// View while requestingif (async.connectionState == ConnectionState.active || async.connectionState == ConnectionState.waiting) {
return Center(
child: Text("loading...")); } /// View when an error occursif (async.connectionState == ConnectionState.done) {
if (async.hasError) {
return Center(
child: Text("error")); }else if(async.hasData && async.data ! = null && async.data.length > 0) { List resultList = async.data;returnListview. builder(Controller: _scrollController, itemCount: ResultList. length + 1, itemExtent: 100.0, itemBuilder: (BuildContext context, int index) {return index < async.data.length ? Container(
child: Card(
child: Row(
children: <Widget>[
Expanded(
child: Container(
child: Text(resultList[index]["title"].toString(),style: TextStyle(fontSize:20),),
padding: EdgeInsets.symmetric(horizontal: 10),
),
flex: 2,
),
Expanded(
child: Container(
child:Image.network(resultList[index]["images"][0].toString()), padding: EdgeInsets.all(5), ), flex: 1, ), ], ), ), height: 50, ): Center( child: isShowProgress? CircularProgressIndicator strokeWidth: (2.0) : the Container (),); }); }else{
return Center(
child: Text("error")); }}return Center(
child: Text("error")); },),Copy the code
RefreshIndicator + ScrollController implement drop down refresh and slide up loading
The code above already loads and displays data asynchronously. For pulled-down refresh, simply nest refreshIndicators outside the FutureBuilder and specify onRefresh.
RefreshIndicator(
onRefresh: getItemNews,
child: FutureBuilder<List<dynamic>>(
future: getDataFuture,
...
)
)
Copy the code
Loading data up via ScrollController:
ScrollController _scrollController = ScrollController();
@override
void initState() {
super.initState();
getDataFuture = getItemNews();
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
print("get more"); _getMore(currentDate); }}); } _getMore(String date) async{if(date == "")
return;
setState(() {
isShowProgress = true;
});
Map<String, dynamic> historyMap ;
response = await dio.get(HISTORY_NEWS + date);
historyMap = response.data;
if(historyMap ! = null &&historyMap.length > 0){
List<dynamic> stories = historyMap["stories"];
if(stories ! = null && stories.length > 0){ currentDate =historyMap["date"].toString();
}
if(response.data["stories"] != null){
items.addAll(response.data["stories"]); }}setState(() {
isShowProgress = false;
});
}
Copy the code
In LisbView, I specify the length of the data for the returned data length + 1, the purpose is to now CircularProgressIndicator on the bottom of the dialog box, and the above variables isShowProgress whether can be controlled according to the component.
github
The last
Welcome to follow the wechat public account “Flutter Programming and Development”.