NestedScrollView内嵌RecyclerView无法滚动到指定item问题求助
问题修复方案
根本原因
你当前计算滚动目标值的坐标体系错误:view.y获取的是RecyclerView子item相对于它的直接父控件(RecyclerView本身)的y轴偏移量,而NestedScrollView的smoothScrollTo方法要求传入的是目标点相对于NestedScrollView直接子布局(即XML中包裹RecyclerView的垂直LinearLayout)的偏移量。你没有把RecyclerView自身在父布局里的偏移量算入目标值,位置越靠后的item计算出来的目标值误差越大,超出ScrollView的可滚动范围后就会直接滚动到底部,只有前几个在可见区域的item因为误差小可以正常滚动。
修复后代码
private fun scrollToPosition(position: Int) { if (position !in 0 until variantsAdapter.itemCount) return val targetItem = binding.variantsRecyclerView.findViewWithTag<ConstraintLayout>("pos_$position") // 目标item还未被RecyclerView渲染时,先让RecyclerView滚动到对应位置触发渲染,再递归调用滚动逻辑 if (targetItem == null) { binding.variantsRecyclerView.scrollToPosition(position) binding.variantsRecyclerView.post { scrollToPosition(position) } return } // 计算目标item在窗口中的绝对坐标 val itemLocation = IntArray(2) targetItem.getLocationInWindow(itemLocation) // 计算NestedScrollView直接子布局在窗口中的绝对坐标 val scrollChildLocation = IntArray(2) binding.nestedScrollView.getChildAt(0).getLocationInWindow(scrollChildLocation) // 计算相对于滚动容器的目标偏移量,避免滚动到负值超出顶部 val targetScrollY = (itemLocation[1] - scrollChildLocation[1]).coerceAtLeast(0) binding.nestedScrollView.post { binding.nestedScrollView.smoothScrollTo(0, targetScrollY) targetItem.requestFocus() } }
优化说明
- 去掉了硬编码的200ms延迟,改用
post方法保证代码在View布局刷新完成后再执行,适配不同性能的设备,避免固定延迟带来的时序问题 - 新增了目标item未渲染的兼容逻辑,即使是非常靠后的未加载item也能正常触发滚动
- 增加了滚动边界判断,避免出现向上滚动超出顶部的异常情况
内容的提问来源于stack exchange,提问作者rdias002
相关产品推荐
相关产品推荐

