美文网首页
Flutter刷新实践 2022-07-18 周一

Flutter刷新实践 2022-07-18 周一

作者: 勇往直前888 | 来源:发表于2022-07-18 11:17 被阅读0次

    简介

    下拉刷新,下拉加载更多,是一个比较普遍的功能。比如一个接口返回一个列表,数据有上百项,甚至更多,一次性全部返回显示不大合适。所以,一般接口会进行分页,提供一个page和pageSize参数,一小部分一小部分地来取数据。
    虽然iOS原生提供这些功能,但是效果很差,一般都会求助于第三方库。Flutter也一样,这个功能也会用第三方库。

    添加

    flutter pub add easy_refresh
    
    dependencies:
      easy_refresh: ^3.0.2+1
    

    链接地址

    easy_refresh: ^3.0.2+1

    flutter_easy_refresh

    3.0是最近的一次大升级,pub上的地址都变了。以前的名字叫flutter_easy_refresh

    构造方法

    这个组件用的最多的是ListView。用法和手势差不多,将需要上拉下拉的ListView作为子组件。

    /// 默认的构造方法
    const EasyRefresh({
        Key? key,
        required this.child,
    //... ....
    })
    
    /// 第2种构造方法
    const EasyRefresh.builder({
        Key? key,
        required this.childBuilder,
    //... ....
    })
    
    • 这个和ListView的构造方法很像,大多数情况下,使用默认的构造方法就可以了。

    • ListView嵌套的时候,就应该带builder的构造方法。physics代表ListView是否可以滑动。将需要上拉下拉的指定为可滑动,内部嵌套的指定为不可滑动。

    • ListView嵌套的情况,内部ListView经常会将shrinkWrap设置为true,这里不能这么做。

    • 参数里只有一个代表子组件的child是必选的,其他的都是可选的。这个也和手势很像。但是实际使用的时候,就这一个参数其实没什么用,需要其他参数一起配合使用。

    上拉下拉

    这是这个组件最核心的两个功能。就像onTap对于GestureDetector组件一样。虽然是可选的,但是大多数情况,这两个参数都是要给的。

      /// Refresh callback.
      /// Triggered on refresh.
      /// When null, disable refresh.
      /// The Header current state is [IndicatorMode.processing].
      /// More see [IndicatorNotifier.onTask].
      final FutureOr Function()? onRefresh;
    
      /// Load callback.
      /// Triggered on load.
      /// When null, disable load.
      /// The Footer current state is [IndicatorMode.processing].
      /// More see [IndicatorNotifier.onTask].
      final FutureOr Function()? onLoad;
    
    • 这里给FutureOr类型可以简单看做Future;一般数据获取都是异步的,例外的情况很少。

    • 一般这两个方法都会调用网络数据访问的API,并且一般会有page,pageSize两个参数。

    • 还有一个要考虑的问题就是确定是否有数据。这个在onLoad方法中需要确定。如果已经没有数据了,那么就不需要再进行网络请求了,同时也要给出相应的提示。

    • 判断是否有更多数据一般有两种方法。一种是接口给出数据的总数,客户端端根据已经收到的数量来判断是否结束。
      另外一种方法是判断本次返回的数量,与pageSize进行比较。如果还有更多数据,那么本次返回的数据量就是pageSize;如果不足的话,那么当前返回的就是最后一点数据了,是最后一个有数据的接口。(就像整除里面的求余,余数肯定比除数要小)

    头和尾

    • 在上拉和下拉过程中,在网络数据请求结束的时候,有一些状态改变,这个都是通过头和尾这两个视图来表现的。可以简单地理解为是ListView的头和尾。

    • 这两个参数是可选的,不给的话,会提供默认的视图。大多数情况下,用默认的也可以凑合。

      /// Header indicator.
      final Header? header;
    
      /// Footer indicator.
      final Footer? footer;
    
    • Header和Footer都继承自Indicator。提供了好多种Header和Footer,可以根据需要进行选择。ClassicHeader和ClassicFooter可以满足大多数情况。

    控制器

    • 和TextField组件类似,提供了一个控制器进行更多的自定义。比如,用代码进行额外的刷新,加载更多,用代码结束刷新或者加载更多等等功能。

    • 大多数情况可以不需要用这个控制器。需要更多控制的时候,可以考虑加。

    • 要注意的是,和TextField组件的控制器类似,控制器需要在组件外部进行初始化。用完之后,要调用dispose方法进行销毁。

    • 如果要使用控制器,那么就要把默认的两个变量改为true

      /// Take over the completion event of the refresh task.
      /// Finish the refresh with [finishRefresh] and return the result.
      final bool controlFinishRefresh;
    
      /// Take over the completion event of the load task.
      /// Finish the load with [finishLoad] and return the result.
      final bool controlFinishLoad;
    
      EasyRefreshController({
        this.controlFinishRefresh = false,
        this.controlFinishLoad = false,
      });
    

    简化的例子

    • 数据逻辑部分(logic):
      ///下拉刷新上拉加载固定写法
      List dataList = [];
      int pageNum = 1;
      final int pageSize = 20;
      bool hadMore = true;
      EasyRefreshController easyRefreshController = EasyRefreshController(
        controlFinishRefresh: true,
        controlFinishLoad: true,
      );
    
      /// 下拉刷新
      Future refreshData() async {
        pageNum = 1;
        hadMore = true;
        dataList = [];
        
        getDataList();
      }
    
      /// 上拉加载更多
      Future loadMoreData() async {
        if (hadMore) {
          pageNum++;
          getDataList();
        } else {
          easyRefreshController.finishLoad(IndicatorResult.noMore);
        }
      }
    
      /// 从网络取数据
      void getDataList() {
        NetworkApi.getDataListFromRemote(
            pageNum: pageNum,
            pageSize: pageSize,
            success: (response) {
              List list = response['data'];
              if (list.length < pageSize) {
                hadMore = false;
              } else {
                hadMore = true;
              }
              if (dataList.isEmpty) {
                easyRefreshController.finishRefresh();
              } else {
                easyRefreshController.finishLoad(
                    hadMore ? IndicatorResult.success : IndicatorResult.noMore);
              }
              dataList.addAll(list);
    
              update();
            },
            fail: (fail) {});
      }
      //下拉刷新上拉加载固定写法
    
    @override
      void onClose() {
        easyRefreshController.dispose();
        super.onClose();
      }
    
    • 界面相关部分(view)
    EasyRefresh(
        controller: logic.easyRefreshController,
        header: ClassicHeader(),
        footer: ClassicFooter,
        onRefresh: logic.refreshData,
        onLoad: logic.loadMoreData,
        child: ListView.builder(
            itemCount: logic.dataList.length,
            itemBuilder: (BuildContext context, int index) {
                Map item = logic.dataList[index] ?? {};
                String name = item['name'] ?? '';
                return Container(
                    height: 44.h,
                    child: Text(name),
                );
            }
        ),
    )
    

    相关文章

      网友评论

          本文标题:Flutter刷新实践 2022-07-18 周一

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