我的编程空间,编程开发者的网络收藏夹
学习永远不晚

android教你打造独一无二的上拉下拉刷新加载框架

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

android教你打造独一无二的上拉下拉刷新加载框架

其实早在去年七月,群里小伙伴就有让我共享这个。但我当时绝的技术不纯熟。代码有bug什么的。没有写出来。现在感觉整理的差不多了。就写出来让大家看看,有问题一起讨论解决。

说到刷新加载,我们第一个想到啥,对了就是swiperefreshlayout,还有什么SuperSwiperefreshlayout,XRecyclerView等等。反正老多了,我还是之前那句话,不管用什么,我们需要知道他的原理。

打造框架开始

对于刷新加载的实现,你们第一个想到的是什么?是用swiperefresh然后在recyclerview底部加一个不同type?还是用事件拦截呢?那必须是事件拦截啊,虽然现在swiperefreshlayout很火,基本很多app都能看到他。但是遇到那种坑比公司说刷新要用自己公司logo你也没辙。对把。。好了,感觉得罪了好多公司,不管他,我们继续。

我们先看下我们的效果图:

老铁,没毛病。下面我介绍如何实现的。

下拉刷新

首先我们给出如下几个参数,后面要用:


  private NestedScrollingParentHelper helper = null;
  private boolean IsRefresh = true;
  private boolean IsLoad = true;
  //滑动的总距离
  private int totalY = 0;
  private LinearLayout headerLayout = null;
  private MyRecyclerView myRecyclerView = null;
  private LinearLayout footerLayout = null;

既然是刷新,我们的滚动肯定是在父view之前的。所以我们需要在onNestedPreScroll这个方法里面写上我们所需要改动的x,y值。

我们需要用父view去拦截它。

我们需要判断dy的值是否大于0,因为大于0是刷新操作,小于0是加载操作。然后我们需要判断recyclerview是否是纵向的而不是横向的。


public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
    if (IsRefresh) {
      if (dy > 0) {
        if (myRecyclerView.isOrientation(0)) {
          totalY += dy;
          if ((totalY / 2) <= 0) {
            scrollTo(0, totalY / 2);
            consumed[1] = dy;
          } else {
            scrollTo(0, 0);
            consumed[1] = 0;
          }
        }
        return;
      }
    }

上拉加载

上面我也说了onNestedPreScroll这个方法中判断dy<0才是加载操作。所以综上所述,代码变成了这样:


 public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
    if (totalY < 0 && myRecyclerView.isOrientation(0) || totalY > 0 && myRecyclerView.isOrientation(1)) {
      isfling = true;
    }
    if (IsRefresh) {
      if (dy > 0) {
        if (myRecyclerView.isOrientation(0)) {
          totalY += dy;
          if ((totalY / 2) <= 0) {
            scrollTo(0, totalY / 2);
            consumed[1] = dy;
          } else {
            scrollTo(0, 0);
            consumed[1] = 0;
          }
        }
        return;
      }
    }
    if (IsLoad) {
      if (dy < 0) {
        if (myRecyclerView.isOrientation(1)) {
          totalY += dy;
          if ((totalY / 2) >= 0) {
            scrollTo(0, totalY / 2);
            consumed[1] = dy;
          } else {
            scrollTo(0, 0);
            consumed[1] = 0;
          }
        }
        return;
      }
    }
  }

最后我们需要在子view滑动结束后,实行如下操作:


 //子view滑动结束调用
  //dyUnconsumed < 0 向下滚
  //dyUnconsumed > 0 向上滚
  public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
    if (dyUnconsumed != 0) {
      totalY += dyUnconsumed;
      scrollTo(0, totalY / 2);
    }
  }

其实最主要的两个方法已经解决了,其他到没什么了,这边,我把nestedscrolling的8个接口的功能和自定义recyclerview放出来。已变大家参考。希望大家都能实现自己的刷新加载。告别swiperefreshlayout。

添加header和footer

这里我们参考listview自带的addheaderview和addfooterview。代码如下:


 public void addHeaderView(View headerView, int headerHeight) {
    this.headerLayout.removeAllViews();
    this.headerLayout.addView(headerView);
    LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, headerHeight);
    layoutParams.topMargin = -headerHeight;
    this.headerLayout.setLayoutParams(layoutParams);
  }
  public void addFooterView(View footerView, int footerHeight) {
    this.footerLayout.removeAllViews();
    this.footerLayout.addView(footerView);
    this.footerLayout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, footerHeight));
  }

几个接口的实现


 public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
    return true;
  }
  public void onNestedScrollAccepted(View child, View target, int axes) {
    helper.onNestedScrollAccepted(child, target, axes);
  }
  //父view拦截子view的滚动
  public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
    if (totalY < 0 && myRecyclerView.isOrientation(0) || totalY > 0 && myRecyclerView.isOrientation(1)) {
      isfling = true;
    }
    if (IsRefresh) {
      if (dy > 0) {
        if (myRecyclerView.isOrientation(0)) {
          totalY += dy;
          if ((totalY / 2) <= 0) {
            scrollTo(0, totalY / 2);
            consumed[1] = dy;
          } else {
            scrollTo(0, 0);
            consumed[1] = 0;
          }
        }
        return;
      }
    }
    if (IsLoad) {
      if (dy < 0) {
        if (myRecyclerView.isOrientation(1)) {
          totalY += dy;
          if ((totalY / 2) >= 0) {
            scrollTo(0, totalY / 2);
            consumed[1] = dy;
          } else {
            scrollTo(0, 0);
            consumed[1] = 0;
          }
        }
        return;
      }
    }
  }
  //子view滑动结束调用
  //dyUnconsumed < 0 向下滚
  //dyUnconsumed > 0 向上滚
  public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
    if (dyUnconsumed != 0) {
      totalY += dyUnconsumed;
      scrollTo(0, totalY / 2);
    }
  }
  public void onStopNestedScroll(View child) {
    helper.onStopNestedScroll(child);
    if (onTouchUpListener != null) {
      isfling = false;
      onTouchUpListener.touchUp();
    }
  }
  public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
    return isfling;
  }
  public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
    return isfling;
  }
  public int getNestedScrollAxes() {
    return helper.getNestedScrollAxes();
  }

自定义recyclerview

既然是自己写的刷新加载框架,总不能还有自定义layout中在放个recyclerview。多麻烦,自定义一个,直接放在里面,然后分别放个header和footer 就没必要每次有页面用到刷新都要写一个布局。3个布局解决整个项目的刷新和加载。话不多说,代码如下:


  private class MyRecyclerView extends RecyclerView {
    private StaggeredGridLayoutManager staggeredGridLayoutManager = null;
    private LinearLayoutManager linearLayoutManager = null;
    private GridLayoutManager gridLayoutManager = null;
    private boolean isScrollLoad = false;
    private boolean isScrollRefresh = false;
    public MyRecyclerView(Context context) {
      super(context);
      setVerticalFadingEdgeEnabled(false);
      setHorizontalFadingEdgeEnabled(false);
      setVerticalScrollBarEnabled(false);
      setHorizontalScrollBarEnabled(false);
      setOverScrollMode(OVER_SCROLL_NEVER);
      setItemAnimator(new DefaultItemAnimator());
    }
    private void setMyLayoutManager(LayoutManager layoutManager) {
      if (layoutManager instanceof StaggeredGridLayoutManager) {
        staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;
      } else if (layoutManager instanceof GridLayoutManager) {
        gridLayoutManager = (GridLayoutManager) layoutManager;
      } else if (layoutManager instanceof LinearLayoutManager) {
        linearLayoutManager = (LinearLayoutManager) layoutManager;
      }
      setLayoutManager(layoutManager);
      if (!isVertical()) {
        throw new NullPointerException("vertical!");
      }
    }
    private boolean isOrientation(int orientation) {//orientation,0代表向下,1代表向上
      if (orientation == 0)
        return isCanPullDown();
      else if (orientation == 1)
        return isCanPullUp();
      return false;
    }
    private boolean isCanPullDown() {
      return !canScrollVertically(-1);
    }
    private boolean isCanPullUp() {
      return !canScrollVertically(1);
    }
//    private int scrollLoad() {
//      int lastItem = 0;
//      int itemCount = 0;
//      int spanCount = 1;
//      if (staggeredGridLayoutManager != null) {
//        lastItem = staggeredGridLayoutManager.findLastVisibleItemPositions(null)[0];
//        itemCount = staggeredGridLayoutManager.getItemCount();
//        spanCount = staggeredGridLayoutManager.getSpanCount();
//      } else if (linearLayoutManager != null) {
//        lastItem = linearLayoutManager.findLastVisibleItemPosition();
//        itemCount = linearLayoutManager.getItemCount();
//        spanCount = 1;
//      } else if (gridLayoutManager != null) {
//        lastItem = gridLayoutManager.findLastVisibleItemPosition();
//        itemCount = gridLayoutManager.getItemCount();
//        spanCount = gridLayoutManager.getSpanCount();
//      }
//      return ((itemCount - 1) / spanCount + 1) - (lastItem / spanCount + 1);
//    }
    private boolean isVertical() {
      if (staggeredGridLayoutManager != null)
        return staggeredGridLayoutManager.getOrientation() == StaggeredGridLayoutManager.VERTICAL;
      else if (linearLayoutManager != null)
        return linearLayoutManager.getOrientation() == LinearLayoutManager.VERTICAL;
      else if (gridLayoutManager != null)
        return gridLayoutManager.getOrientation() == GridLayoutManager.VERTICAL;
      return false;
    }
//    public void onScrolled(int dx, int dy) {
//      if (dy > 0 && !isScrollLoad) {
//        if (oLior != null) {
//          onScrollListener.scrollLoad(sc````````
`
``
llLoad());//传递滚动到倒数第几行
//        }
//      }
//    }
  }

这样我们变实现了自己的刷新加载框架,代码我已上传:SWPullRecyclerLayout_jb51.rar

您可能感兴趣的文章:Android中使用RecyclerView实现下拉刷新和上拉加载Android下拉刷新上拉加载控件(适用于所有View)Android实现上拉加载更多以及下拉刷新功能(ListView)Android RecyclerView实现下拉刷新和上拉加载Android RecyclerView 上拉加载更多及下拉刷新功能的实现方法Android ListView实现上拉加载更多和下拉刷新功能Android使用recyclerview打造真正的下拉刷新上拉加载效果Android开发之ListView列表刷新和加载更多实现方法Android ListView下拉刷新上拉自动加载更多DEMO示例Android刷新加载框架详解


免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

android教你打造独一无二的上拉下拉刷新加载框架

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

android教你打造独一无二的上拉下拉刷新加载框架

其实早在去年七月,群里小伙伴就有让我共享这个。但我当时绝的技术不纯熟。代码有bug什么的。没有写出来。现在感觉整理的差不多了。就写出来让大家看看,有问题一起讨论解决。 说到刷新加载,我们第一个想到啥,对了就是swiperefreshlayo
2022-06-06

Android使用recyclerview打造真正的下拉刷新上拉加载效果

前言 前段时间需要用到recyclerview,就想找个封装好的下拉刷新,上拉加载的库,结果愣是没找到,便自己写了一个。 注意:我说的是“上拉加载”,不是滑到底部自动加载。 虽然现在自动加载是主流和趋势,但也不排除有时候就需要用到上拉加载啊
2022-06-06

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录