Flutter|Flutter EasyRefresh+ListView+Scoped Model 实现上拉刷新和分页加载

前言:
Flutter项目需要实现“上拉刷新和分页加载“的功能,分页可以把大量数据分割成一个个小段,分次加载。这样可以有效避免因为一次load全部数据而导致客户端变慢的问题。在这里我使用EasyRefresh第三方插件来实现下拉刷新和分页加载的操作。
用到的知识点:

  1. dio实现网络请求的数据
  2. model层封装“上拉刷新和分页加载“的方法
  3. ui层使用easyrefresh实现下拉刷新,分页加载
  4. ui层使用listview展示列表信息
实现的步骤:
【Flutter|Flutter EasyRefresh+ListView+Scoped Model 实现上拉刷新和分页加载】1.在pubspec.yaml添加sdk
dependencies: ... cupertino_icons: ^0.1.0 dio: ^2.1.9 scoped_model: ^1.0.1 flutter_easyrefresh: ^1.2.7

2.请求数据
//请求数据的方法 Future getListData(BuildContext context) async { String url = IHttpService.baseUrl +"&offset=$currentPage&limit=$limit"; //接口 DioUtil.getInstance().get(context, url).then((res) {//DioUtil是自定义封装网络请求的工具类 if (res.statusCode == Response.ok) { var responseList = res.data; if (responseList != null) { _listData = https://www.it610.com/article/responseList["loans"]; } } else { _listData= https://www.it610.com/article/[]; } }).catchError((onError) { }).whenComplete(this.notifyListeners); }

3.上拉刷新数据
//上拉刷新数据的方法 Future refreshData(BuildContext context) async { currentPage = 0; _listData.clear(); getListData(context); return null; }

4.加载更多数据
//加载更多数据的方法 Future loadMoreData(BuildContext context) async { String url = IHttpService.baseUrl +"&offset=$currentPage&limit=$limit"; //接口 DioUtil.getInstance().get(context, url).then((res) { if (res.statusCode == Response.ok) { var responseList = res.data; if (responseList != null) { var listData = https://www.it610.com/article/responseList["loans"]; currentPage += limit; //每次加载的条数 if (currentPage > 0) { List list1 = List(); list1.addAll(_listData); list1.addAll(listData); _listData= list1; } } } else { _listData= https://www.it610.com/article/[]; } }).catchError((onError) { }).whenComplete(this.notifyListeners); }

5.easyrefresh实现下拉刷新,分页加载
Widget _buildListView(BuildContext context, CommonStateModel model) { return new EasyRefresh( onRefresh: () => _onListRefresh(context), //下拉刷新 loadMore: () => _onListLoadMore(context), //分页加载更多 key: _easyRefreshKey, refreshHeader: MaterialHeader( //Material风格的头部刷新 key: _headerKey, ), refreshFooter: MaterialFooter( //Material风格的底部刷新 key: _footerKey, ), child: _buildListViewContent(context, model), ); }

6.listview展示列表信息
Widget _buildListViewContent(BuildContext context, CommonStateModel model) { return ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), itemBuilder: (context, index) { return renderRow(context, model, index); }, itemCount: model.listData.length, controller: _scrollController, ); }//自定义的列表项 Widget renderRow(BuildContext context, CommonStateModel model, int i) { var itemData = https://www.it610.com/article/model.listData[i]; return new InkWell( child: new Container( decoration: new BoxDecoration(color: Colors.white), margin: const EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 0.0), child: new Row( children: [ new Expanded( flex: 1, child: new Padding( padding: const EdgeInsets.all(5.0), child: new Container( height: 120.0, child: new Center( child: Image.asset(images/logo.png), ), ), )), new Expanded( flex: 2, child: new Padding( padding: const EdgeInsets.all(5.0), child: new Column( children: [ new Text(itemData["name"]) ... ], ), ), ), new Image.asset("images/arrow_right_icon.png", height: 25.0, width: 25.0) ], ), ), onTap: () { //To do something }, ); }

7.Model层封装“上拉刷新和分页加载“的完整代码
import 'package:scoped_model/scoped_model.dart'; class CommonStateModel extends Model { int currentPage = 0; int limit = 4; //每次分页加载的条数var _listData; get listData => _listData; //请求数据的方法 Future getListData(BuildContext context) async { //接口 String url = IHttpService.baseUrl +"&offset=$currentPage&limit=$limit"; //接口 DioUtil.getInstance().get(context, url).then((res) { //DioUtil是自定义封装网络请求的工具类 if (res.statusCode == Response.ok) { var responseList = res.data; if (responseList != null) { _listData = https://www.it610.com/article/responseList["loans"]; } } else { _listData= https://www.it610.com/article/[]; } }).catchError((onError) { }).whenComplete(this.notifyListeners); }//上拉刷新数据的方法 Future refreshData(BuildContext context) async { currentPage = 0; _listData.clear(); getListData(context); return null; }//加载更多数据的方法 Future loadMoreData(BuildContext context) async { String url = IHttpService.baseUrl +"&offset=$currentPage&limit=$limit"; //接口 DioUtil.getInstance().get(context, url).then((res) { if (res.statusCode == Response.ok) { var responseList = res.data; if (responseList != null) { var listData = https://www.it610.com/article/responseList["loans"]; currentPage += limit; //每次分页加载的条数 if (currentPage > 0) { List list1 = List(); list1.addAll(_listData); list1.addAll(listData); _listData= https://www.it610.com/article/list1; } } } else { _listData= []; } }).catchError((onError) { }).whenComplete(this.notifyListeners); }static CommonStateModel of(context) => ScopedModel.of(context, rebuildOnChange: true); }

8.UI层实现上拉刷新和分页加载的完整代码
import 'package:flutter_easyrefresh/easy_refresh.dart'; import 'package:flutter_easyrefresh/material_header.dart'; import 'package:flutter_easyrefresh/material_footer.dart'; import 'package:scoped_model/scoped_model.dart'; ...class HomePage extends StatefulWidget { @override State createState() => HomePageState(); }class HomePageState extends State with AutomaticKeepAliveClientMixin { CommonStateModel commonStateModel; GlobalKey _easyRefreshKey = new GlobalKey(); GlobalKey _headerKey = new GlobalKey(); GlobalKey _footerKey = new GlobalKey(); ScrollController _scrollController = ScrollController(); _getModel() { if (commonStateModel == null) { commonStateModel = CommonStateModel(); } return commonStateModel; }//请求数据的方法 void _initListData(BuildContext context) async { await commonStateModel.getListData(context); }//上拉刷新的方法 Future _onListRefresh(BuildContext context) async { await commonStateModel.refreshData(context); }//分页加载更多的方法 Future _onListLoadMore(BuildContext context) async { await commonStateModel.loadMoreData(context); }@override void initState() { super.initState(); _getModel(); _initListData(context); }@override Widget build(BuildContext context) { super.build(context); return ScopedModel( model: commonStateModel, child: ScopedModelDescendant( builder: (context, child, model) { return Scaffold( body: Container( decoration: new BoxDecoration(color: Color(0xFFECECEB)), child: _buildListView(context, model), ), ); }, ), ); }//使用easyrefresh实现下拉刷新,分页加载的方法 Widget _buildListView(BuildContext context, CommonStateModel model) { return new EasyRefresh( onRefresh: () => _onListRefresh(context), loadMore: () => _onListLoadMore(context), key: _easyRefreshKey, refreshHeader: MaterialHeader( //Material风格的头部刷新 key: _headerKey, ), refreshFooter: MaterialFooter( //Material风格的底部刷新 key: _footerKey, ), child: _buildListViewContent(context, model), ); }//listview展示列表信息的方法 Widget _buildListViewContent(BuildContext context, CommonStateModel model) { return ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), itemBuilder: (context, index) { return renderRow(context, model, index); }, itemCount: model.listData.length, controller: _scrollController, ); }Widget renderRow(BuildContext context, CommonStateModel model, int i) { var itemData = https://www.it610.com/article/model.listData[i]; return new InkWell( child: new Container( decoration: new BoxDecoration(color: Colors.white), margin: const EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 0.0), child: new Row( children: [ new Expanded( flex: 1, child: new Padding( padding: const EdgeInsets.all(5.0), child: new Container( height: 120.0, child: new Center( child: Image.asset(Image.asset(images/logo.png)), ), ), )), new Expanded( flex: 2, child: new Padding( padding: const EdgeInsets.all(5.0), child: new Column( children: [ new Text[itemData["name"]] ... ], ), ), ), new Image.asset("images/arrow_right_icon.png", height: 25.0, width: 25.0) ], ), ), onTap: () { //To do something }, ); }@override void dispose() { super.dispose(); _scrollController.dispose(); }@protected bool get wantKeepAlive => true; }

9.总结:
在Flutter项目已经实现”上拉刷新和分页加载“的功能, 如果有什么疑问的话,可以留言联系我哦!
转载于:https://my.oschina.net/wupeilin/blog/3075903

    推荐阅读