You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

嵌套RecyclerView平滑滚动到position 0时部分元素不显示

问题原因

这个异常是嵌套RecyclerView回收复用逻辑冲突导致的:

  1. 你为每个内嵌RecyclerView单独创建了独立的RecycledViewPool,同时开启了recycleChildrenOnDetach = true。父RV执行smoothScrollToPosition(0)快速滚动时,离屏的父项会被回收,对应子RV的子View会被存入子RV自己的独立回收池;当父项被重新复用绑定到屏幕上时,独立回收池和新绑定的子RV实例没有正确关联,子View无法被取出重新布局。
  2. 你给子RV设置了isNestedScrollingEnabled = false,子RV不会参与父RV的嵌套滚动布局协调,复用时不会主动触发重算;如果子RV高度是随内容自适应的,setHasFixedSize(true)还会让系统跳过measure步骤,直接导致子RV区域空白,同项其他非RV内容因为走了正常的bind和布局流程所以可以正常显示。
  3. 如果你在父项的onBindViewHolder里每次都重新new子RV的LayoutManager和Adapter,也会导致子RV的布局状态在快速滚动复用时丢失。
修复步骤
  • 移除子RV单独创建独立回收池的逻辑,所有同类型的子RV共享父RV持有的同一个回收池,只在父RV初始化时创建一次即可:
// 父RV初始化时执行一次
val sharedChildPool = RecyclerView.RecycledViewPool()
parentRecyclerView.setRecycledViewPool(sharedChildPool)

// 子RV绑定时直接传入共享池,不要new新的RecycledViewPool
childRecyclerView.setRecycledViewPool(sharedChildPool)
  • 子RV的LayoutManager和Adapter不要在每次onBindViewHolder时重复创建,放到父项ViewHolder的构造函数里初始化一次,避免复用时状态丢失:
class ParentItemViewHolder(itemView: View, onChildItemClick: OnChildItemClick) : RecyclerView.ViewHolder(itemView) {
    private val childRv = itemView.findViewById<RecyclerView>(R.id.child_recycler_view)
    // 构造时一次性初始化LayoutManager
    private val childLayoutManager = GridLayoutManager(itemView.context, 2).apply {
        recycleChildrenOnDetach = true
    }
    private val childAdapter = ChildAdapter(onChildItemClick)

    init {
        childRv.layoutManager = childLayoutManager
        childRv.adapter = childAdapter
        childRv.isNestedScrollingEnabled = false
        // 子RV高度如果是wrap_content自适应,必须删掉setHasFixedSize(true)这行
        // childRv.setHasFixedSize(true)
    }

    fun bind(data: DatesModelObject) {
        childAdapter.oldList = data.list
        childAdapter.notifyDataSetChanged()
        // 绑定数据后主动触发布局请求,修正复用时的空白问题
        childRv.requestLayout()
    }
}
  • 如果快速滚动后还是偶现空白,可以给父RV加滚动状态监听,滚动停止后给当前屏幕可见的子RV主动触发一次布局刷新:
parentRecyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
    override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
        if (newState == RecyclerView.SCROLL_STATE_IDLE) {
            val lm = recyclerView.layoutManager as LinearLayoutManager
            for (i in lm.findFirstVisibleItemPosition()..lm.findLastVisibleItemPosition()) {
                val holder = recyclerView.findViewHolderForAdapterPosition(i) as? ParentItemViewHolder ?: continue
                holder.itemView.findViewById<RecyclerView>(R.id.child_recycler_view)?.requestLayout()
            }
        }
    }
})

内容的提问来源于stack exchange,提问作者Chuy Porras

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 15:54:21