总结:判断 RecyclerView 中 View 的可见性

获取 RecyclerView 当前屏幕中可见 item 下标

我们只需要设置对 RecyclerView 设置滑动监听即可(当 RecyclerView 停下滑动时进行检测):

override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
    super.onScrollStateChanged(recyclerView, newState)
    if (newState == RecyclerView.SCROLL_STATE_IDLE) {
        emitVisibleItems()
    }
}

override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
    super.onScrolled(recyclerView, dx, dy)

    if (dx == 0 && dy == 0) {
        emitVisibleItems()
    }
}

fun emitVisibleItems() {
    val manager = recyclerView.layoutManager
    if (manager is LinearLayoutManager) {
        val firstPosition = manager.findFirstVisibleItemPosition()
        val lastPosition = manager.findLastVisibleItemPosition()
        val visibleRange = mutableListOf<Int>()
        for (i in firstPosition..lastPosition) {
            val view = manager.findViewByPosition(i) ?: continue
            val rect = Rect()
            val isVisible = view.getGlobalVisibleRect(rect)
            if (isVisible) {
                visibleRange.add(i)
            }
        }
        // iVisualItems 是 VisibleItemsListener 类型,回调接口
        iVisualItems.onItemsVisible(visibleRange)
    }
}


interface VisibleItemsListener {
    fun onItemsVisible(items: List<Int>)
}

这里是 LinearLayoutManager 为例,其他 Manager 也是类似,都有类似的 findFirstVisibleItemPosition() 和 findLastVisibleItemPosition() 方法。

*** 还有类似的findFirstCompletelyVisiblePosition() 和 findLastCompletelyVisiblePosition() 方法可供使用,当然意义是不同的** ****

判断 RecyclerView 某个 View 是否完全显示
/**
 * 调用此方法最好延时 16ms (即一帧)
 */
fun isCompletelyVisible(): Boolean {
    val rect = Rect()
    val isVisible = view.getGlobalVisibleRect(rect)
    return isVisible && (rect.bottom - rect.top >= view.height)
}

实际上这个方法应该可以用于判断任何 View,只不过在 RecyclerView 中更常见。为啥需要总结这个呢,因为出于最近业务上的一个需求:

在这里插入图片描述

如图所示,这是 RecyclerView 中的一个 itemView,原本的逻辑是整项滑出后,播放器停止播放(这里我们可以通过对播放器 View 设置addOnAttachStateChangeListener(),然后在其onViewDetachedFromWindow()回调方法里进行处理)。有一天产品改了逻辑:只要播放器 View 不是完全可见,就停止播放,当然原来的逻辑也需要保留,因为需要防止滑动过快时视频无法自动停止。这里我们就可以综合 1,2两点,通过 RecyclerView 的局部刷新方法进行联系即可实现功能,示例代码如下:

const val ITEM_MOST_VISIBLE = 1
override fun onItemsVisible(items: List<Int>) {
    items.forEach{ position -> 
    	adapter.notifyItemChanged(position, ITEM_MOST_VISIBLE)
    }
}
@Override
public void onBindViewHolder(@NonNull BaseViewHolder holder, int position, @NonNull List<Object> payloads) {
    if (!payloads.isEmpty()) {
        // ..... 
    } 
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值