总结:判断 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 中 View 的可见性_第1张图片

如图所示,这是 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()) {
        // ..... 
    } 
}

你可能感兴趣的:(Android,android,RecyclerView,View,可见性)