美文网首页Flutter中文社区一起来学Flutter~Flutter圈子
Flutter 17: 图解 ListView 下拉刷新与上拉加

Flutter 17: 图解 ListView 下拉刷新与上拉加

作者: 阿策神奇 | 来源:发表于2018-09-30 16:23 被阅读3次

          小菜上次学 ListView 时,只学习了一下异步请求数据加载新闻和 Loading 等待的小知识点,但对于新闻列表数据的更新和加载更多是必不可少的,而实现【下拉刷新】与【上划加载更多】的方式有很多种,今天小菜整理一下使用三方库 flutter_refresh 来实现列表的数据更新。
          小菜也是再偶然间看到有大神用到这个三方库的,小菜想要尝试的原因主要是因为一是因为 flutter_refresh 集成很简单,不用单独写头部样式和底部加载时的 loading 等;二是小菜技术太有限,对 Flutter 的未知有太多,想多尝试几种方式。

    集成方式

    1. pubspec.yaml 中 添加 flutter_refresh : ^0.0.2,并同步 packages get
    2. 在相应的 .dart 文件中添加引用 import 'package:flutter_refresh/flutter_refresh.dart';
    3. 数据加载时暂时不用 ListView 变更为 new Refresh,小菜主要是处理 onHeaderRefresh 下拉刷新onFooterRefresh 底部刷新 两个方法中的数据处理。小菜的测试接口需要根据每一页的最后一个新闻ID 和 整个的新闻数量为参数值进行处理。
    // 顶部刷新
    Future<Null> onHeaderRefresh() {
      return new Future.delayed(new Duration(seconds: 2), () {
        setState(() {
          rowNumber = 0;
          lastFileID = '0';
          newsListBean = null;
          getNewsData(lastFileID, rowNumber);
        });
      });
    }
    // 底部刷新
    Future<Null> onFooterRefresh() async {
      return new Future.delayed(new Duration(seconds: 2), () {
        setState(() {
          getNewsData(lastFileID, rowNumber);
        });
      });
    }
    // 接口数据处理
    getNewsData(var lastID, var rowNum) async {
      await http
          .get(
              'https://...?lastFileID=${lastID}&rowNumber=${rowNum}')
          .then((response) {
        if (response.statusCode == 200) {
          var jsonRes = json.decode(response.body);
          newsListBean = NewsListBean(jsonRes);
          if (lastID == '0' && rowNum==0 && dataItems != null) {
             dataItems.clear();
          }
          setState(() {
            if (newsListBean != null &&
                newsListBean.list != null &&
                newsListBean.list.length > 0) {
              for (int i = 0; i < newsListBean.list.length; i++) {
                dataItems.add(newsListBean.list[i]);
              }
              lastFileID = newsListBean.list[newsListBean.list.length - 1].fileID
                  .toString();
              rowNumber += newsListBean.list.length;
            } else {}
          });
        }
      });
    }
    
    Widget childFreshWidget() {
      Widget childFreWi;
      if (dataItems != null && dataItems.length != 0) {
        childFreWi = new Padding(
          padding: EdgeInsets.all(6.0),
          child: new Refresh(
            onFooterRefresh: onFooterRefresh,
            onHeaderRefresh: onHeaderRefresh,
            childBuilder: (BuildContext context,
                {ScrollController controller, ScrollPhysics physics}) {
              return new Container(
                  child: new ListView.builder(
                physics: physics,
                controller: controller,
                itemCount: rowNumber,
                itemBuilder: (context, item) {
                  return buildListData(context, dataItems[item]);
                },
              ));
            },
          ),
        );
      } else {
        childFreWi = new Stack(
          children: <Widget>[
            new Padding(
              padding: new EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 35.0),
              child: new Center( child: SpinKitFadingCircle( color: Colors.blueAccent, size: 30.0, ), ),
            ),
            new Padding(
              padding: new EdgeInsets.fromLTRB(0.0, 35.0, 0.0, 0.0),
              child: new Center( child: new Text('正在加载中,莫着急哦~'), ),
            ),
          ],
        );
      }
      return childFreWi;
    }
    
    下拉刷新 上拉加载更多

    问题小结

          小菜在测试过程中遇到了很多的小问题,现在逐一整理一下。

    问题一:初始化进入页面后,加载完第一页之后刷新数据不加载,第二次刷新数据才加载,且加载的是上一次刷新的数据?
    解决方式:
    1. 进入页面时调用数据接口 initState(),为了保证第一次正常加载;
    2. getNewsData() 中一定一定要添加 setState(() {}); 小菜在测试时,每次刷新接口都会正常调用,但是都是第二次刷新才加载第一次刷新的数据,接口是正常的,但是数据总是慢一拍,小菜测试发现因为没有用 setState(() {}); 以后一定要注意,这样才可以实时进行更新。
    问题二:下拉刷新过程中,接口数据重复加载?
    解决方式:

          小菜目前还没有涉及缓存等方面的,单纯的一个下拉刷新应该是重新调用初始的接口,首先要清空列表,不然接口数据重复实实在在会出现的。

    Future<Null> onHeaderRefresh() {
      return new Future.delayed(new Duration(seconds: 2), () {
        setState(() {
          rowNumber = 0;
          lastFileID = '0';
          if (dataItems != null) {
             dataItems.clear();
          }
          getNewsData(lastFileID, rowNumber);
        });
      });
    }
    
    问题三:根据问题二的解决方案,显示正常,但是运行时 Log 报错,提示 Widget 已创建?
    解决方案:

          小菜测试了很久,把这个判断列表制空从 onHeaderRefresh() 中移到数据处理的 getNewsData() 方法中,虽然不是非常理解,但是问题可以正常解决,小菜的理解是 onHeaderRefresh() 中处理的是数据和 Widget,而小菜自己的方法中是单纯的数据处理。

    if (lastID == '0' && rowNum==0 && dataItems != null) {
      dataItems.clear();
    }
    

          小菜刚接触 Flutter 时间不长,还有很多不清楚和不理解的地方,如果又不对的地方还希望多多指出。以下是小菜公众号,欢迎闲来吐槽~

    公众号

    相关文章

      网友评论

      • bfd2249505d6:是我一直没关注还是你换了名字??以前一直是小菜?不是和尚?
        阿策神奇:@Sevewing 简书是小菜,公众号是和尚

      本文标题:Flutter 17: 图解 ListView 下拉刷新与上拉加

      本文链接:https://www.haomeiwen.com/subject/rfmwoftx.html