1.场景再现:
有一个需求需要获取RecycleView中点击的某个item距离布局顶部的距离。如图所示
我的思路就是去获取我点击的RecycleView中的item,然后通过
view.getTop();
这个方法去获得距离顶部的值。那么如何去获取RecycleView中的item,我当时想到的就是调用
recyclerView.getChildAt(index)
这个方法。于是我把点击的
值传了进去,该值是通过
onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position)
方法中的position获得,在第一屏点击的时候显示正常,但当我滑动一段距离以后点击直接报了我一个空异常。通过getChildAt(index)方法获取的居然是null,比较疑惑。
2.寻找原因
对于
onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position)
这个回调方法很熟悉了,这个position对应的就是显示出来的item位置,正常情况肯定不会是null,那么猜测问题出在
getChildAt(index)
这个方法,看源码,发现里面内容如下。
public View getChildAt(int index) {
if (index < 0 || index >= mChildrenCount) {
return null;
}
return mChildren[index];
}
可知此处的index是mChildren数组中的位置,那么mChildren又是什么呢? 发现代码说明如下
// Child views of this ViewGroup
private View[] mChildren;
即是ViewGroup容器中的view,而RecycleView中的item即ViewGroup中的view,在不可见时,会被移除出RecycleView(即ViewGroup)。因而mChildren的数量即为屏幕可见item个数。所以原因找到了,当在第一屏时,由于显示的view与recycleview中的item顺序是对应的,所以没有问题。而当Recycleview顶部有不可见item时,getChildAt(index)中的index应该为recycleview点击位置数减去顶部不可见的个数,如果不减,position个数有可能大于可见View的个数,即报null。
3.规律总结
public View getChildAt(int index)
方法中的index对应RecycleView中可见item的位置数。
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position) {}
该position 对应item在RecycleView中的位置数,包括可见以及不可见,未生成的。
那么回归到开始的问题,如何才能获取到recyeclew中点击的item距离布局顶部的高度呢? 步骤如下:
- 1.获取对应item在mChild中的位置即position - firstVisbleItemPosition
- 2.通过getChildAt(int index) 获取对应的View
- 3.通过view.getTop()获取到对应的距离