当前位置:主页 > android教程 > Android Flutter下拉刷新

Android Flutter实现自定义下拉刷新组件

发布:2023-03-02 11:30:02 59


给网友朋友们带来一篇相关的编程文章,网友衡博文根据主题投稿了本篇教程内容,涉及到Android、Flutter下拉刷新组件、Android、下拉刷新、Flutter下拉刷新、Android Flutter下拉刷新相关内容,已被972网友关注,涉猎到的知识点内容可以在下方电子书获得。

Android Flutter下拉刷新

前言

Flutter开发中官方提供了多平台的下拉刷新组件供开发者使用,例如RefreshIndicatorCupertinoSliverRefreshControl分别适配AndroidiOS下拉刷新交互形态。但实际情况中这两者使用情况却不太相同在使用场景就存在差异,RefreshIndicator作为嵌套型下拉组件列表内容作为它的child使用而CupertinoSliverRefreshControl是嵌入在Sliver列表中使用。同时对于交互设计来说一般更偏好RefreshIndicator下拉形式,通过下拉列表整体下移后透出拉下刷新组件样式。

改造点

DIY下拉组件样式

RefreshIndicator下拉组件样式可能会在交互上不符合设计师要求。例如下拉过程中loading样式出现交互是会和列表重合,实际需求可能是希望下拉过程中loading样式和列表一样同步下移出现。

因此修改原有的下拉刷新组件样式构建,构建方法入参主要是refreshState、pulledExtent、refreshTriggerPullDistance、refreshIndicatorExtent。原逻辑中组件偏量是固定不变_kActivityIndicatorMargin值,因此下拉组件样式是直接显示出来的。

调整方案根据pulledExtent下拉距离,默认偏移下拉组件样式自身高度加上下拉距离从而将偏移量从负方向向正方向展示。

 Widget buildRefreshIndicator(
      BuildContext context,
      RefreshIndicatorMode refreshState, //下拉状态
      double pulledExtent, // 下拉实时距离
      double refreshTriggerPullDistance, // 下拉限制最大高度
      double refreshIndicatorExtent, // 下拉组件最大高度
      ) {
    return Container(
    color: Colors.deepOrange,
    child: Stack(
      clipBehavior: Clip.none,
      children: [
        Positioned(
          top: -refreshIndicatorExtent + pulledExtent,
          left: 0.0,
          right: 0.0,
          //简易的下拉样式 忽略refreshState状态
          child: Container(
            child: Text("我是下拉呀~~~~",style: TextStyle(color: Colors.white,fontSize: 20,),textAlign: TextAlign.center,),
          ),
        ),
      ],
    ),
  );
  }

刷新时机调整

RefreshIndicator下拉组件另外刷新触发交互点也不是设计交互期望的逻辑,它的刷新触发机制是只要下拉超过设置下拉距离并会触发。但实际开发中可能并不希望当到达对应点就去做刷新操作而是下拉到一定距离松手后才会触发,因此需要改造下拉刷新组件内部的刷新机制。

原下拉刷新逻辑如下关键代码所示,只要当RefreshIndicatorMode.drag状态下并且latestIndicatorBoxExtent > widget.refreshTriggerPullDistance时就会触发下拉刷新方法。

  RefreshIndicatorMode transitionNextState() {
    RefreshIndicatorMode nextState;
。、、、 、、、 省略
      drag:
      case RefreshIndicatorMode.drag:
        if (latestIndicatorBoxExtent == 0) {
          return RefreshIndicatorMode.inactive;
        } else if (latestIndicatorBoxExtent < widget.refreshTriggerPullDistance) {
          return RefreshIndicatorMode.drag;
        } else {
          // 当latestIndicatorBoxExtent > widget.refreshTriggerPullDistance就执行
          if (widget.onRefresh != null) { //刷新逻辑执行点
            HapticFeedback.mediumImpact();
            SchedulerBinding.instance.addPostFrameCallback((Duration timestamp) {
              refreshTask = widget.onRefresh()..whenComplete(() {
                if (mounted) {
                  setState(() => refreshTask = null);
                  refreshState = transitionNextState();
                }
              });
              setState(() => hasSliverLayoutExtent = true);
            });
          }
          return RefreshIndicatorMode.armed;
        }
        break;
      case RefreshIndicatorMode.armed:
        if (refreshState == RefreshIndicatorMode.armed && refreshTask == null) {
          goToDone();
          continue done;
        }

        if (latestIndicatorBoxExtent > widget.refreshIndicatorExtent) {
          return RefreshIndicatorMode.armed;
        } else {
          nextState = RefreshIndicatorMode.refresh;
        }
        continue refresh;
      refresh:
      case RefreshIndicatorMode.refresh:
        if (refreshTask != null) {
          return RefreshIndicatorMode.refresh;
        } else {
          goToDone();
        }
        continue done;
      	、、、、、省略
    }

    return nextState;
  }

弱希望下拉松手后判断是否触发刷新只修改RefreshIndicator下拉组件似乎无法直接满足条件。因此需要结合手势监听来完成,需要对整体框架代码做一个调整。

增加Listener嵌套监听手势抬起操作,获取MagicSliverRefreshControlState(原是私有类放开为公有)判断是否是超出下拉最小刷新间距,对内部是否可刷新标记进行赋值操作。

GlobalKey key = GlobalKey();

Listener(
      child: CustomScrollView(
        physics: BouncingScrollPhysics(),
        slivers: [
          MagicSliverRefreshControl(
            key: key,
            builder: buildRefreshIndicator,
            onRefresh: () async {
              print("<> SliverRefreshControl onRefresh start");
              await Future.delayed(Duration(seconds: 2),(){});
              print("<> SliverRefreshControl onRefresh end");
            },
          ),
          SliverList(
            delegate: SliverChildBuilderDelegate(
                  (content, index) {
                return Common.getWidget(index);
              },
              childCount: 100,
            ),
          )
        ],
      ),
      onPointerUp: (event){ //判断是否可刷新操作
        if(key?.currentState?.isCanRefreshAction() ?? false){
          key?.currentState?.canRefresh = true;
        }else{
          key?.currentState?.canRefresh = false;
        }
      },
    );

RefreshIndicator组件内部增加一种新状态RefreshIndicatorMode.over用来判断是否刷新临界状态,结合外部手势抬手监听。当下拉超出刷新最小间距且抬手放开判断触发刷新操作,over恢复到drag还是进入armed都是通过以上条件来实现的,其他原逻辑保持不变。

switch (refreshState) {
      case RefreshIndicatorMode.inactive:
        if (latestIndicatorBoxExtent <= 0) {
          return RefreshIndicatorMode.inactive;
        } else {
          nextState = RefreshIndicatorMode.drag;
        }
        continue drag;
      drag:
      case RefreshIndicatorMode.drag:
        if (latestIndicatorBoxExtent == 0) {
          return RefreshIndicatorMode.inactive;
        }
        else if (latestIndicatorBoxExtent < widget.refreshTriggerPullDistance) {
          return RefreshIndicatorMode.drag;
        } else {
          return RefreshIndicatorMode.over; //增加一种状态 表示下拉满足刷新条件
        }
        break;
    	/// 进入新状态后结合抬手后是否可刷新标记为判断是进入刷新方法还是回到拖拽状态
      case RefreshIndicatorMode.over:
        if (latestIndicatorBoxExtent <= widget.refreshTriggerPullDistance) {
          if(canRefresh){
            canRefresh = false; //将刷新标记置空复位
            if (widget.onRefresh != null) {
              HapticFeedback.mediumImpact();
              SchedulerBinding.instance.addPostFrameCallback((Duration timestamp) {
                refreshTask = widget.onRefresh()..whenComplete(() {
                  if (mounted) {
                    setState(() => refreshTask = null);
                    refreshState = transitionNextState();
                  }
                });
                setState(() => hasSliverLayoutExtent = true);
              });
            }
            return RefreshIndicatorMode.armed;
          }else{
            return RefreshIndicatorMode.drag;
          }
        }
        return RefreshIndicatorMode.over;
        break;

效果展示

具体代码看这里

调整前

调整后

以上就是Android Flutter实现自定义下拉刷新组件的详细内容,更多关于Android Flutter下拉刷新的资料请关注码农之家其它相关文章!


参考资料

相关文章

  • Android开发之ViewPager实现滑动切换页面

    发布:2023-03-10

    这篇文章主要为大家详细介绍了Android开发之ViewPager实现滑动切换页面,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下


  • Android利用Canvas标点画线并加入位移动画(2)

    发布:2023-03-09

    这篇文章主要为大家详细介绍了Android利用Canvas标点画线并加入位移动画的第二篇,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下


  • Android ViewPager2 使用及自定义指示器视图实现

    发布:2023-03-10

    这篇文章主要为大家介绍了Android ViewPager2 使用及自定义指示器视图实现详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪


  • Android开发使用Databinding实现关注功能mvvp

    发布:2023-03-08

    这篇文章主要为大家介绍了Android开发使用Databinding实现关注功能mvvp示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪


  • Android虚拟机与类加载机制详情

    发布:2023-03-05

    这篇文章主要介绍了Android虚拟机与类加载机制详情,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下


  • Android中FileProvider的各种场景应用详解

    发布:2023-03-05

    这篇文章主要为大家介绍了Android中FileProvider的各种场景应用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪


  • Android中分析Jetpack Compose动画内部的实现原理

    发布:2023-03-04

    这篇文章主要介绍了Android中分析Jetpack Compose动画内部的实现原理,文章围绕主题展开详细的内容介绍,具有一定的参考价值,感兴趣的小伙伴可以参考一下


  • Android项目中引入aar包的正确方法介绍

    发布:2023-03-02

    生成aar之后下一步就是如何引用本地的aar文件,下面这篇文章主要给大家介绍了关于Android项目中引入aar包的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下


网友讨论