NestedScrollView内容变更后自动滚动到顶部,如何保持原有滚动高度?
问题根因
你遇到的滚动回弹问题,本质是筛选后RecyclerView更新数据触发全局重布局,NestedScrollView会自动调整滚动位置到默认聚焦的子View,最终滚动到页面顶部。
解决方案
下面按优先级从高到低给出可行方案:
方案1:修改布局属性(优先选用,无需额外代码)
在你现有布局的RecyclerView节点中补充以下属性即可:
<androidx.recyclerview.widget.RecyclerView android:id="@+id/list" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="24dp" android:focusable="false" android:focusableInTouchMode="false" android:nestedScrollingEnabled="false" android:isScrollContainer="false" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
说明:
- 禁用RecyclerView的焦点获取能力,避免NestedScrollView滚动到RecyclerView位置
- 禁用嵌套滚动,避免ScrollView和RecyclerView的滚动事件冲突
- 明确指定layoutManager,减少重布局时的测量计算
方案2:手动记录恢复滚动位置
如果修改布局后仍有问题,可以在筛选逻辑中手动保存和恢复滚动位置:
Kotlin 示例代码
// 点击筛选按钮时先记录当前滚动偏移 val currentScrollY = nested_scrollView.scrollY // 执行你的筛选逻辑,更新Adapter数据集 adapter.setNewData(filteredList) // 等待布局重绘完成后恢复滚动位置 nested_scrollView.post { nested_scrollView.scrollTo(0, currentScrollY) }
Java 示例代码
// 记录滚动位置 int currentScrollY = nestedScrollView.getScrollY(); // 执行筛选、更新Adapter adapter.setNewData(filteredList); // 恢复滚动位置 nestedScrollView.post(() -> nestedScrollView.scrollTo(0, currentScrollY));
方案3:使用DiffUtil局部更新列表
替换原有全局调用notifyDataSetChanged()的更新方式,改用DiffUtil计算新旧数据集差异,仅局部更新变化的条目,不会触发整个页面重布局,从根源避免滚动跳转,同时大幅提升列表更新性能。
内容的提问来源于stack exchange,提问作者Fivos
相关产品推荐
相关产品推荐

