Android获取RecyclerView滑动距离方法详细讲解
作者:AllenC6 发布时间:2021-07-04 23:21:32
先说能用的究极解决方案,大家着急的直接复制走,以后想了解再过来看
没有header,且所有Item的高度一致
private fun getScrollYDistance(recyclerView: RecyclerView): Int? {
kotlin.runCatching {
val layoutManager = recyclerView.layoutManager as LinearLayoutManager
val position = layoutManager.findFirstVisibleItemPosition()
val firstVisibleChildView = layoutManager.findViewByPosition(position)
val itemHeight = firstVisibleChildView!!.height
return position * itemHeight - firstVisibleChildView.top
}
return null
}
有一个header,其他所有Item高度一致
var headerHeight = 0
private fun getScrollYDistance(recyclerView: RecyclerView): Int? {
kotlin.runCatching {
val layoutManager = recyclerView.layoutManager as LinearLayoutManager
val position = layoutManager.findFirstVisibleItemPosition()
if (position == 0) {
val headerView = layoutManager.findViewByPosition(0)
headerHeight = headerView!!.height
}
val firstVisibleChildView = layoutManager.findViewByPosition(position)
val itemHeight = firstVisibleChildView!!.height
return if (position == 0) {
position * itemHeight - firstVisibleChildView.top
} else {
(position - 1) * itemHeight - firstVisibleChildView.top + headerHeight
}
}
return null
}
有多个header,其他Item一致
Integer[] headerHeightArray;
private int getScollYDistance(){
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getRecyclerView().getLayoutManager();
// 获取第一个可见item的位置
int position = layoutManager.findFirstVisibleItemPosition();
// 获取第一个可见item
View firstVisiableChildView = layoutManager.findViewByPosition(position);
// 必须考虑有没有Header 预存下所有header的高度
int headerCount = adapter.getHeaderCount();
if (headerCount > 0) {
if (headerHeightArray == null) {
headerHeightArray = new Integer[headerCount];
}
if (position < headerCount) {
View headerView_i = layoutManager.findViewByPosition(position);
headerHeightArray[position] = headerView_i.getHeight();
}
}
// 获取第一个可见item的高度
int itemHeight = firstVisiableChildView.getHeight();
// 获取第一个可见item的位置
int distance = 0;
if (position == 0) {
distance = position * itemHeight - firstVisiableChildView.getTop();
} else {
int allHeaderHeight = 0;
for (int i = 0; i < Math.min(position,headerCount); i++) {
allHeaderHeight = allHeaderHeight + headerHeightArray[i];
}
distance = (position - Math.min(position,headerCount)) * itemHeight - firstVisiableChildView.getTop() + allHeaderHeight;
}
return distance;
}
注意调用位置:
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
getScollYDistance();
}
});
试过的一些想法,都有一些问题,有的可以弥补,有的直接玩完
RecyclerView 虽然有getScrollX() 和 getScrollY(), 但是测试发现这两个函数总是返回0,太无语了。因此想到了下面几种方法来实现获取滑动距离:
利用OnScrollListener
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
private int totalDy = ;
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
totalDy -= dy;
}
});
如代码所述,totalDy的确保存了 RecyclerView 的滑动距离,但是当我向下滑动 RecyclerView ,之后插入/删除/移动 Item 的时候,totalDy 就变得不精确了;比如删除或者插入新的Item,那么totalDy就不能再回归到 0了。这个可以通过当删除或者插入时来对totalDy进行加减相应的高度。
totalDy = recyclerView.computeVerticalScrollOffset();
然而compute方法计算出的并不是滑动的精确距离,stackOverflow上有答案解释其为 item 的平均高度 * 可见 item 数目,不是我们需要的精确距离。
totalDy = recyclerView.getChildAt().getTop();
依靠第一个item的滑动距离来进行动画的设置,但是根据该方法得出的 totalDy 在滑动到一定程度后清零。
这是因为recyclerViewl.getChildAt(0) 返回的永远是第一个可见的child,不是所有view list 的第一个child,因此这种用法是得不到滑动距离的。
另外下面这三种用法都是等价的,都是获取第一个可见的child:
LinearLayoutManager layoutManager = (LinearLayoutManager) this.getLayoutManager();
View firstVisiableChildView = this.getChildAt();
View firstVisiableChildView = layoutManager.getChildAt()
int position = layoutManager.findFirstVisibleItemPosition();
View firstVisiableChildView = layoutManager.getChildAt(position)
但是下面这种就不是获取第一个可见的child,而是获得所有view list 的第一个child。但是滑动一段距离后它总是返回null,即第一个child被recycle后,总是返回null。
//Don't use this function to get the first item, it will return null when the first item is recycled.
LinearLayoutManager layoutManager = (LinearLayoutManager) this.getLayoutManager();
View child2 = layoutManager.findViewByPosition();
来源:https://blog.csdn.net/m0_37707561/article/details/128641390


猜你喜欢
- 今天遇到文件上传的问题,使用Ajax方式进行提交,服务器一直报错The current request is not a multipart
- 本文实例讲述了Java内部类对象的创建及hook机制。分享给大家供大家参考,具体如下:Java中的内部类虽然在状态信息上与其外围类在状态信息
- 本文实例为大家分享了C#支付宝新版支付请求接口调用的具体代码,供大家参考,具体内容如下因为支付宝已经集成了完整的SDK,所以可以使用SDK直
- OKhttp3中的cookiesOkHttpClient client = new OkHttpClient().newBuilder().
- Java中使用也比较简单:1. 编译正则表达式的字面值得到对应的模式Pattern对象;2. 创建匹配给定输入与此模式的匹配器Matcher
- Json是一种类似于XML的通用数据交换格式,具有比XML更高的传输效率. 从结构上看,所有的数据(data)最终都可以分解成三种类型: 第
- 在logback.xml中加上该配置,包名如:com.xxx<logger name="packageName"
- 需求:将 一个容器List<Bean> 按照一定的字段进行分组,分组过后的值为特定的BEAN 里面的属性例如:假定有这样一个Be
- vscode Java 开发环境配置博客地址VsCode官网教程系统需安装jdk1.8,配置好环境变量JAVA_HOME 打开vscode,
- 本文纯干货,贴上PDF文档操作类C#代码,需要添加iTextSharp.dll引用才可以正常通过编译。废话不多说了,直接给大家贴代码了。代码
- MyBatis简介MyBatis前身是iBatis,是一个基于Java的数据持久层/对象关系映射(ORM)框架.MyBatis是对JDBC的
- 项目结构这个是在网上找的资源,出处记不得了,记录一下。程序的总体结构,很简单的:核心代码代码如下:ArrComparator.java类im
- java转换字符串编码格式 (解码错误,重新解码)字符集概念:规定了某个文字对应的二进制数字存放方式(编码)和某串二进制数值代表了哪个文字(
- 1.强引用( Strong Reference )最普遍的引用:Object obj=new Object()抛出OutOfMemoryEr
- @CacheEvict无法解决分页缓存清除当下比较热门的spring缓存就是encache,但是最近在写毕业设计的时候,发现了在缓存分页的时
- 本文实例讲述了C#微信公众号开发之接收事件推送与消息排重的方法。分享给大家供大家参考。具体分析如下:微信服务器在5秒内收不到响应会断掉连接,
- 前言在原生的 Android 或 iOS 中,都提供了基本的键值对存储方式,Android 是 SharedPreferences,iOS
- 大多数的B2C商城项目都会有限时活动,当用户下单后都会有支付超时时间,当订单超时后订单的状态就会自动变成已取消 ,这个功能的实现
- kotlin是一门基于jvm的编程语言,最近进行了关于kotlin和 anko的研究。并且结合现在的APP设计模式,设想了初步的开发方式。并
- java函数中的传值和传引用问题一直是个比较“邪门”的问题,其实java函数中的参数都是传递值的,所不同的是对于基本数据类型传递的是参数的一