滚动时如何获取父项内完全绘制的子RecyclerView顶部可见项位置
解决嵌套RecyclerView获取屏幕顶部可见子项位置的问题
问题分析
你遇到的核心问题是:子RecyclerView的LayoutManager判断可见性是基于自身的视图边界,而非屏幕的可视区域。即使父RecyclerView的item部分滚出屏幕,子RecyclerView内部的所有item在自身范围内都是完全可见的,因此findFirstVisibleItemPosition()始终返回0。此外,你之前的代码存在ID不匹配的问题(item布局中子RecyclerView的ID是rcvEventList,但代码中查找的是childRecyclerView),这会导致获取错误的视图。
解决方案
要获取屏幕上真正可见的子RecyclerView项,需要将子item的坐标转换为全局屏幕坐标,再与屏幕可视区域对比,筛选出最顶部的可见项。具体步骤如下:
1. 修正布局与代码的ID匹配
确保item布局中的子RecyclerView ID与代码中一致,例如修改item_design布局:
<androidx.recyclerview.widget.RecyclerView android:id="@+id/childRecyclerView" android:layout_width="20dp" android:layout_height="match_parent" />
2. 实现滚动监听逻辑
在父RecyclerView的滚动监听器中,遍历所有可见的父项,逐个处理子RecyclerView,计算每个子item的屏幕坐标并筛选:
parentRecyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) // 获取屏幕可视区域的全局坐标 val screenVisibleRect = Rect() recyclerView.getGlobalVisibleRect(screenVisibleRect) // 获取父RecyclerView中所有可见的父项ViewHolder val visibleParentViewHolders = recyclerView.findVisibleViewHolderItems() var topVisibleChildPos = -1 var minScreenTop = Int.MAX_VALUE // 遍历每个可见的父项 for (parentVH in visibleParentViewHolders) { val childRcv = parentVH.itemView.findViewById<RecyclerView>(R.id.childRecyclerView) val childLM = childRcv.layoutManager as LinearLayoutManager val childItemCount = childLM.itemCount // 遍历子RecyclerView的所有item(因子Rcv完全绘制,所有item都有视图) for (pos in 0 until childItemCount) { childLM.findViewByPosition(pos)?.let { childView -> val childItemRect = Rect() childView.getGlobalVisibleRect(childItemRect) // 判断子item是否与屏幕可视区域相交 if (Rect.intersects(screenVisibleRect, childItemRect)) { // 记录顶部最靠上的子item位置 if (childItemRect.top < minScreenTop) { minScreenTop = childItemRect.top topVisibleChildPos = pos } } } } } Timber.d("屏幕顶部可见的子RecyclerView项位置: $topVisibleChildPos") } })
关键逻辑说明
- 全局坐标转换:通过
getGlobalVisibleRect()获取视图在屏幕中的绝对位置,而非相对于父布局的位置。 - 可见区域判断:使用
Rect.intersects()判断子item是否有部分或全部位于屏幕可视范围内。 - 筛选最顶部项:遍历所有符合条件的子item,记录屏幕顶部坐标最小的项,即为屏幕上最顶部的可见子项。
内容的提问来源于stack exchange,提问作者anil
相关产品推荐
相关产品推荐

