ScrollView嵌套RecyclerView无法滚动到指定item位置问题求解
问题根因
你的滚动失效是三个错误叠加导致的:
- 传入
smoothScrollTo的第二个参数是像素偏移量,你直接传RecyclerView的条目position(从0开始的序号),两个值的单位、含义完全不一样,不可能滚到正确位置。 - 外层ScrollView高度设为
wrap_content,这种模式下ScrollView会把内部所有子控件全量展开,自身可滚动高度为0,所有scroll相关方法调用都会失效。 - ScrollView和RecyclerView同属可滚动控件,你没有处理嵌套滚动冲突,直接操作外层ScrollView根本拿不到内层RecyclerView未渲染条目的位置信息。
修复步骤
1. 先修正布局问题
把普通ScrollView换成支持嵌套滚动的NestedScrollView,高度改为match_parent,同时给RecyclerView关闭嵌套滚动,避免滚动冲突:
<androidx.core.widget.NestedScrollView android:id="@+id/scrollView" android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/contentreyclerpager" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingTop="10dp" android:nestedScrollingEnabled="false"/> </RelativeLayout> </androidx.core.widget.NestedScrollView>
如果RecyclerView外面没有其他需要和它一起滚动的内容,直接删掉外层NestedScrollView,单独用RecyclerView,直接调用
recyclerView.smoothScrollToPosition(targetPosition)就能实现需求,性能更好也没有滚动冲突问题。
2. 修正滚动逻辑
不要直接传条目position,先计算目标条目相对于ScrollView的真实像素偏移,再执行滚动:
private fun focusOnView( scroll: NestedScrollView, recyclerView: RecyclerView, targetPosition: Int ) { scroll.post { // 先查找目标位置的ViewHolder,没渲染出来就先触发RecyclerView定位 val targetHolder = recyclerView.findViewHolderForAdapterPosition(targetPosition) if (targetHolder == null) { recyclerView.scrollToPosition(targetPosition) // 等下一帧布局完成再重新计算偏移 scroll.post { focusOnView(scroll, recyclerView, targetPosition) } return@post } // 计算目标条目相对于ScrollView顶部的真实偏移量,扣除RecyclerView的paddingTop值 val targetOffset = recyclerView.top + targetHolder.itemView.top - recyclerView.paddingTop scroll.smoothScrollTo(0, targetOffset) } }
避坑提示
- 不要把
NestedScrollView.FOCUS_DOWN、scroll.bottom这类值当偏移量传入,前者是系统焦点查找的常量值,后者是ScrollView控件自身的底部坐标,都不是滚动需要的内容偏移值。 - 滚动调用必须放在布局完成之后执行,你之前用
post投递任务的写法是对的,如果是页面首次加载就触发滚动,建议把调用时机放在RecyclerView的布局完成回调里,不要直接在onCreate里同步调用。
内容的提问来源于stack exchange,提问作者MazMM
相关产品推荐
相关产品推荐

