其实早在去年七月,群里小伙伴就有让我共享这个。但我当时绝的技术不纯熟。代码有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
# 刷新框架
# 下拉刷新框架
# 下拉刷新上拉加载框架
# Android通用LoadingView加载框架详解
# android基于dialog实现等待加载框示例
# Android图片加载框架Glide的基本用法介绍
# Android 常见的图片加载框架详细介绍
# Android实现自定义加载框的代码示例
# 详解Android之图片加载框架Fresco基本使用(一)
# 详解Android之图片加载框架Fresco基本使用(二)
# 一起动手编写Android图片加载框架
# 设计简单的Android图片加载框架
# Android自定义加载框效果
# 加载
# 自定义
# 自己的
# 几个
# 第一个
# 都能
# 要用
# 的是
# 我也
# 上滚
# 让我
# 是在
# 好了
# 放在
# 才是
# 就有
# 你也
# 说了
# 但我
# 说到
相关文章:
javascript中对象的定义、使用以及对象和原型链操作小结
如何自己制作一个网站链接,如何制作一个企业网站,建设网站的基本步骤有哪些?
建站之星图片链接生成指南:自助建站与智能设计教程
实现虚拟支付需哪些建站技术支撑?
如何在阿里云虚拟机上搭建网站?步骤解析与避坑指南
如何快速搭建高效服务器建站系统?
制作充值网站的软件,做人力招聘为什么要自己交端口钱?
网站图片在线制作软件,怎么在图片上做链接?
,巨量百应是干嘛的?
如何在腾讯云服务器快速搭建个人网站?
专业商城网站制作公司有哪些,pi商城官网是哪个?
长春网站建设制作公司,长春的网络公司怎么样主要是能做网站的?
佛山网站制作系统,佛山企业变更地址网上办理步骤?
高端智能建站公司优选:品牌定制与SEO优化一站式服务
Python文件管理规范_工程实践说明【指导】
建站一年半SEO优化实战指南:核心词挖掘与长尾流量提升策略
网站制作的步骤包括,正确网址格式怎么写?
宁波免费建站如何选择可靠模板与平台?
C#如何序列化对象为XML XmlSerializer用法
专业制作网站的公司哪家好,建立一个公司网站的费用.有哪些部分,分别要多少钱?
JS中使用new Date(str)创建时间对象不兼容firefox和ie的解决方法(两种)
香港服务器网站生成指南:免费资源整合与高速稳定配置方案
如何快速搭建自助建站会员专属系统?
如何选择高效便捷的WAP商城建站系统?
,想在网上投简历,哪几个网站比较好?
制作宣传网站的软件,小红书可以宣传网站吗?
建站之星五站合一营销型网站搭建攻略,流量入口全覆盖优化指南
网页制作模板网站推荐,网页设计海报之类的素材哪里好?
建站之星备案流程有哪些注意事项?
如何彻底删除建站之星生成的Banner?
小型网站建站如何选择虚拟主机?
建站之星代理商如何保障技术支持与售后服务?
招贴海报怎么做,什么是海报招贴?
Python多线程使用规范_线程安全解析【教程】
如何用PHP快速搭建CMS系统?
ui设计制作网站有哪些,手机UI设计网址吗?
黑客入侵网站服务器的常见手法有哪些?
开源网站制作软件,开源网站什么意思?
零基础网站服务器架设实战:轻量应用与域名解析配置指南
如何构建满足综合性能需求的优质建站方案?
css网站制作参考文献有哪些,易聊怎么注册?
如何零基础开发自助建站系统?完整教程解析
网站制作新手教程,新手建设一个网站需要注意些什么?
韩国网站服务器搭建指南:VPS选购、域名解析与DNS配置推荐
家庭建站与云服务器建站,如何选择更优?
网站建设制作、微信公众号,公明人民医院怎么在网上预约?
如何选购建站域名与空间?自助平台全解析
建站主机服务器选型指南与性能优化方案解析
建站之星如何防范黑客攻击与数据泄露?
网页设计网站制作软件,microsoft office哪个可以创建网页?
*请认真填写需求信息,我们会在24小时内与您取得联系。