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

原创
2019/07/18 17:45
阅读数 4.9K

前言:

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

用到的知识点:

  1. dio实现网络请求的数据
  2. model层封装“上拉刷新和分页加载“的方法
  3. ui层使用easyrefresh实现下拉刷新,分页加载
  4. ui层使用listview展示列表信息

实现的步骤:

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 = responseList["loans"];
        }
      } else {
        _listData= [];
      }
    }).catchError((onError) {     
    }).whenComplete(this.notifyListeners);
  }

3.上拉刷新数据

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

4.加载更多数据

//加载更多数据的方法
Future loadMoreData(BuildContext context) async {
    page += 1;//每次加载的条数
    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 = responseList["loans"];      
            List list1 = List();
            list1.addAll(_listData);
            list1.addAll(listData);
            _listData= list1;
          
        }
      } else {       
        _listData= [];
      }
    }).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 = 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: <Widget>[
            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: <Widget>[
                   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 = 1;
  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 = responseList["loans"];
        }
      } else {
        _listData= [];
      }
    }).catchError((onError) {     
    }).whenComplete(this.notifyListeners);
  }

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

  //加载更多数据的方法
  Future loadMoreData(BuildContext context) async {
     page += 1;//每次分页加载的条数
     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 = responseList["loans"];          
             List list1 = List();
             list1.addAll(_listData);
             list1.addAll(listData);
             _listData= list1;      
        }
      } else {       
        _listData= [];
      }
    }).catchError((onError) {     
    }).whenComplete(this.notifyListeners);
  }

  static CommonStateModel of(context) =>
      ScopedModel.of<CommonStateModel>(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<StatefulWidget> createState() => HomePageState();
}

class HomePageState extends State<HomePage>
    with AutomaticKeepAliveClientMixin {
  CommonStateModel commonStateModel;
  GlobalKey<EasyRefreshState> _easyRefreshKey =
      new GlobalKey<EasyRefreshState>();
  GlobalKey<RefreshHeaderState> _headerKey =
      new GlobalKey<RefreshHeaderState>();
  GlobalKey<RefreshFooterState> _footerKey =
      new GlobalKey<RefreshFooterState>();

  ScrollController _scrollController = ScrollController();

  _getModel() {
    if (commonStateModel == null) {
      commonStateModel = CommonStateModel();
    }
    return commonStateModel;
  }

  //请求数据的方法
  void _initListData(BuildContext context) async {
    await commonStateModel.getListData(context);
  }

  //上拉刷新的方法
  Future<Null> _onListRefresh(BuildContext context) async {
    await commonStateModel.refreshData(context);
  }

  //分页加载更多的方法
  Future<Null> _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<CommonStateModel>(
      model: commonStateModel,
      child: ScopedModelDescendant<CommonStateModel>(
        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 = 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: <Widget>[
            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: <Widget>[
                   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项目已经实现”上拉刷新和分页加载“的功能, 如果有什么疑问的话,留言联系我哦!

展开阅读全文
打赏
2
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
2
分享
返回顶部
顶部