如何正确地获取RecyclerView当前可视Item位置信息与getChildAt的一些思考

如何正确地获取RecyclerView当前可视Item位置信息与getChildAt的一些思考

解决思路:根据Scroll事件,通过LayoutManager获取对应的位置信息

mRvCouponList.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                if (newState == SCROLL_STATE_IDLE || newState == SCROLL_STATE_DRAGGING) {
                    // DES: 找出当前可视Item位置
                    RecyclerView.LayoutManager layoutManager = mRvCouponList.getLayoutManager();
                    if (layoutManager instanceof LinearLayoutManager) {
                        LinearLayoutManager linearManager = (LinearLayoutManager) layoutManager;
                        mFirstVisiblePosition = linearManager.findFirstVisibleItemPosition();
                        mLastVisiblePosition = linearManager.findLastVisibleItemPosition();
                    }
                }
            }

            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
            }
        });

private void test(){
    Log.i("Rayman","输出当前可视化Item位置:"+ mFirstVisiblePosition +"\t"+ mLastVisiblePosition);
}

上面的方法是正确的,但是需要注意的是,第一次进入页面的时候。RecyclerView没有触发任何滚动的情况下,mLastVisiblePosition返回是0的。为了解决这个问题,需要我们将mLastVisiblePosition的位置尽可能往后设置,或者与第一页加载出来的数据量作为关联


即在数据加载回调的时候添加如下的一个处理

// 假设这是后台返回的数据
List<String> testString = xxx.getData();

if(mLastVisiblePosition == 0){
    if(testString != null && testString.size() > 0){
        mLastVisiblePosition = testString.size();
    }
}

View的可视化视图区间就可以正常确定了。


假设我们有这样的一个操作:一般拿到这个FirstVisiblePosition和LastVisiblePosition的目的都在于,获取当前可视化的Item视图,或者对当前可视化的Item视图都做某一系列的操作。所以都免不了通过getChildAt的方式获取View,但是getChildAt这个API,和我想象中的还有点区别。基于上面的操作目的,之前我是这样写的。

// 刷新当前item
Log.i("Rayman", "输出起始:" + mFirstItemIndex + "\n" + "结束:" + mLastItemIndex);
for (int i = mFirstItemIndex; i < mLastItemIndex ; i++) {
    Log.i("Rayman", "输出当前获取的Item:" + mRvList.getChildAt(i));
        if (mRvList.getChildAt(i) != null) {
        TimerTextView textView = (TimerTextView) mRvList.getChildAt(i);
        textView.refreshData();
    }
}

很直观的就认为,getChildAt这个函数,传递的position是一个相对于RecyclerView来说的绝对位置。例如数据在第十条,我们就很习以为常地传递一个10到这个getChildAt中,期待他能返回第十条数据的视图。


之后看了下文档,文档中也只是含糊地说了下返回指定position的视图,假若在视图组里面获取不到视图,则返回null。基于API的这个解析,会很理所当然地认为这样的理解是完全没问题的。

/**
 * Returns the view at the specified position in the group.
 *
 * @param index the position at which to get the view from
 * @return the view at the specified position or null if the position
 *         does not exist within the group
 */
public View getChildAt(int index) {
    if (index < 0 || index >= mChildrenCount) {
        return null;
    }
    return mChildren[index];
}

但是发现,效果确实是大庭相径,按照上面获取到的mFirstVisiblePosition和mLastVisiblePosition。例如当前一页显示了4条数据,mFirstVisiblePosition不为0,假设mFirstVisiblePosition = 4,那么mLastVisiblePosition则为7了。
image
看到结果,怎么获取到的itemView都是空的?..


但是当我尝试传递0的时候,尼玛…对象竟然不是空的,按照我之前习以为常的想法,第0条视图都已经不在可视范围内了…怎么可能不为空呢?简直颠覆自己的思想,那我思维就需要变化了,假若他在传递0的时候对象不为空,那是不是我传递 1 2 3都不为空呢?
image

果不其然,从上面我传递0到123开始…都侧面地证实了一个现实。


代码修改一下下,改为这样的遍历方式就正常了,将最后一个可视的position减去第一个可视的position,位置就能正常了。

Log.i("Rayman", "输出起始:" + mFirstItemIndex + "\n" + "结束:" + mLastItemIndex);
for (int i = 0; i < mLastItemIndex - mFirstItemIndex ; i++) {
    Log.i("Rayman", "输出当前获取的Item:" + mRvList.getChildAt(i));
        if (mRvList.getChildAt(i) != null) {
        TimerTextView textView = (TimerTextView) mRvList.getChildAt(i);
        textView.refreshData();
    }
}

原来getChildAt(position),position原本就是指代当前可视化Item的位置,而不是绝对位置。例如当前有三条数据,假若我要对可见的第一条Item做处理,就需要传递getChildAt(0),完全不管他复不复用。

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值