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

目录
  • 前言
  • 改造点
    • DIY下拉组件样式
    • 刷新时机调整
  • 效果展示

前言

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: <Widget>[
        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<MagicSliverRefreshControlState> key = GlobalKey<MagicSliverRefreshControlState>();

Listener(
      child: CustomScrollView(
        physics: BouncingScrollPhysics(),
        slivers: <Widget>[
          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下拉刷新的资料请关注我们其它相关文章!

(0)

相关推荐

  • Flutter 给列表增加下拉刷新和上滑加载更多功能

    有状态组件 当 Flutter 的页面需要动态更新数据的时候,就会涉及到 UI 组件需要根据数据变化更新,此时也就意味着组件有了"状态".这就类似 React 的类组件和函数组件(只是后续 React 使用了勾子函数实现了函数组件也可以有状态).在 Flutter 中,组件也分为无状态组件(StatelessWidget)和有状态组件(StatefulWidget),一般尽量使用无状态组件.但是如果组件本身需要维护自身状态的时候,就需要使用有状态组件了.有状态组件的定义形式如下: //

  • Android实现简单的下拉刷新控件

    背景:列表控件在Android App开发中用到的场景很多.在以前我们用ListView,GradView,现在应该大多数开发者都已经在选择使用RecyclerView了,谷歌给我们提供了这些方便的列表控件,我们可以很容易的使用它们.但是在实际的场景中,我们可能还想要更多的能力,比如最常见的列表下拉刷新,上拉加载.上拉刷新和下拉加载应该是列表的标配吧,基本上有列表的地方都要具体这个能力.虽然刷新这个功能已经有各种各样的第三方框架可以选择,但是毕竟不是自己的嘛,今天我们就来实现一个自己的下拉刷新控

  • Flutter 实现下拉刷新上拉加载的示例代码

    本文介绍了Flutter 实现下拉刷新上拉加载的示例代码,分享给大家,具体如下: 效果图 使用方法 添加依赖 dependencies: pull_to_refresh: ^1.5.7 导入包 import 'package:pull_to_refresh/pull_to_refresh.dart'; 页面代码样例 class _MyHomePageState extends State<MyHomePage> { List<String> items = ["1&quo

  • Android自定义实现淘宝下拉刷新效果

    概述 目前下拉刷新的样式是多饰多样,今天我们一起来自定义淘宝下拉刷新,其实淘宝下拉刷新比较的简单就是一个圆环和一个小箭头的显示和隐藏,那么先看看我们的实现的效果. 是不是和淘宝有点像呢?那么现在我们来看看如何实现这个效果.我们这里为了省事,提供了2张照片  第一是"随时随地,想淘就淘"的照片,第二种就是小箭头照片,这里就自己画了,主要就是实现那个圆弧的绘制和旋转动画了.首先说这里的下拉刷新我用的是比较有名的 https://github.com/chrisbanes/Android-P

  • Android 实现的下拉刷新效果

    下面是自己实现的效果: 1.分析 可以将动画分解成: 睁眼毛驴绕着中心地球旋转,并且在到达地球中心时,切换为闭眼毛驴,最后发射出去 地球自我旋转,随着下拉而缓缓上升,达到半径距离后停止上升 一颗上下来回移动的卫星 2.实现 (1)下载赶集app,然后将其后缀名改为zip解压获取我们需要的资源图片: (2) 我们先实现卫星的上下移动 核心代码: @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Matrix

  • Flutter listview如何实现下拉刷新上拉加载更多功能

    目录 下拉刷新 RefreshIndicator 上拉加载更多 总结: 下拉刷新 在Flutter中系统已经为我们提供了google material design的刷新功能 , 样式与原生Android一样. 我们可以使用RefreshIndicator组件来实现Flutter中的下拉刷新,下面们还是先来看下如何使用吧 RefreshIndicator 构造方法: const RefreshIndicator({ Key key, @required this.child, this.disp

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

    目录 前言 改造点 DIY下拉组件样式 刷新时机调整 效果展示 前言 在Flutter开发中官方提供了多平台的下拉刷新组件供开发者使用,例如RefreshIndicator和CupertinoSliverRefreshControl分别适配Android和iOS下拉刷新交互形态.但实际情况中这两者使用情况却不太相同在使用场景就存在差异,RefreshIndicator作为嵌套型下拉组件列表内容作为它的child使用而CupertinoSliverRefreshControl是嵌入在Sliver列

  • Android Scroller及下拉刷新组件原理解析

    Android事件拦截机制 Android中事件的传递和拦截和View树结构是相关联的,在View树中,分为叶子节点和普通节点,普通节点有子节点只能是ViewGroup,叶子节点可以是View或者ViewGroup.Android和事件分发拦截相关的方法有 dispatchTouchEvent(MotionEvent ev) 事件分发相关的方法,沿着View树将一个用户的触摸事件向下分发. onInterceptTouchEvent(MotionEvent ev) 在dispatchTouchE

  • Android自定义组合控件之自定义下拉刷新和左滑删除实例代码

    绪论 最近项目里面用到了下拉刷新和左滑删除,网上找了找并没有可以用的,有比较好的左滑删除,但是并没有和下拉刷新上拉加载结合到一起,要不就是一些比较水的结合,并不能在项目里面使用,小编一着急自己组合了一个,做完了和QQ的对比了一下,并没有太大区别,今天分享给大家,其实并不难,但是不知道为什么网上没有比较好的Demo,当你的项目真的很急的时候,又没有比较好的Demo,那么"那条友谊的小船儿真是说翻就翻啊",好了,下面先来具体看一下实现后的效果吧: 代码已经上传到Github上了,小伙伴们记

  • Android仿百度外卖自定义下拉刷新效果

    现如今的APP各式各样,同样也带来了各种需求,一个下拉刷新都能玩出花样了,前两天订饭的时候不经意间看到了"百度外卖"的下拉刷新,今天的主题就是它–自定义下拉刷新动画. 看一下实现效果吧: 动画 我们先来看看Android中的动画吧: Android中的动画分为三种: Tween动画,这一类的动画提供了旋转.平移.缩放等效果. Alpha – 淡入淡出 Scale – 缩放效果 Roate – 旋转效果 Translate – 平移效果 Frame动画(帧动画),这一类动画可以创建一个D

  • Android自定义下拉刷新上拉加载

    本文实例为大家分享了Android自定义下拉刷新上拉加载的具体实现步骤,供大家参考,具体内容如下 实现的方式是SwipeRefreshLayout + RecyclerView 的VIewType 首先看效果: 总的思路: 布局文件 <android.support.v4.widget.SwipeRefreshLayout android:layout_marginTop="?attr/actionBarSize" android:id="@+id/one_refres

  • Android 仿硅谷新闻下拉刷新/上拉加载更多

    1.添加加载更多布局 1_初始化和隐藏代码 在RefreshListView构造方法中调用 private void initFooterView(Context context) { View footerView = View.inflate(context, R.layout.refresh_listview_footer, null); //隐藏代码 footerView.measure(0, 0); int footerViewHeight = footerView.getMeasur

  • Android使用ListView实现下拉刷新及上拉显示更多的方法

    本文实例讲述了Android使用ListView实现下拉刷新及上拉显示更多的方法.分享给大家供大家参考,具体如下: 今天得需求是做listview+上下拉动在header和footer显示progressdialog,但不影响用户操作 直接上代码,我已经加上注释了,自己看. package com.stay.main; import java.net.HttpURLConnection; import java.util.ArrayList; import java.util.HashMap;

  • Flutter实现自定义下拉选择框的示例详解

    在一些列表页面中,我们经常会有上方筛选项的的需求,点击出现一个下拉菜单,多选.单选.列表选等,而在Flutter中,并没有现成的这样的组件,找第三方的扩展有时候又会受到一定限制,所以最好我们可以自己做一个,这样即使扩展我们也会得心应手. 先看效果图: 关键点:弹出.收回动画.状态改变.选项联动 思路: 我们可以看到一个完整的下拉框有头部和具体的下拉选项两部分组成,头部又和下拉组进行了联动, 把头部当做1个数组,下方选项作为1个数组,两个数组数量一致之间形成一个完整的下拉选择框可以更好的控制联动效

  • Android微信端的下拉刷新功能

    在Android和iOS上对于下拉刷新的处理方法: 在微信公众号内,在面对下拉刷新这个问题上,Android和iOS都自己的表现方式: iOS: Android: 所以我们要给内容加载监听器 function bindEvent() { document.addEventListener('touchstart', touchSatrtFunc, false); document.addEventListener('touchmove', touchMoveFunc, false); docum

  • Jquery Easyui自定义下拉框组件使用详解(21)

    本文实例为大家分享了Jquery Easyui自定义下拉框组件的实现代码,供大家参考,具体内容如下 加载方式 JS调用加载 自定义下拉框不能通过标签的方式进行创建. <input id="box" /> <script> $(function () { //JS 加载调用 $('#box').combo({ required : true, multiple : true, }); }); </script> 属性列表 <script>

随机推荐