Android RecyclerView:notifyItemRemoved如何无动画且不滚动至顶部?
RecyclerView移除条目后保持滚动位置的解决方案
一、取消动画并锁定滚动位置
notifyItemRemoved触发的默认动画会导致RecyclerView重新计算布局,进而引发滚动偏移,分页场景下移除底部条目时问题尤其明显。可以通过临时禁用动画+手动恢复滚动位置解决:
// 1. 记录当前滚动的精确位置 LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); int firstVisiblePos = layoutManager.findFirstVisibleItemPosition(); View firstVisibleView = layoutManager.findViewByPosition(firstVisiblePos); int topOffset = firstVisibleView != null ? firstVisibleView.getTop() : 0; // 2. 禁用RecyclerView的变更动画 recyclerView.getItemAnimator().setSupportsChangeAnimations(false); // 3. 执行数据移除并通知 int removePosition = homeItems.size() - 1; homeItems.remove(removePosition); yourAdapter.notifyItemRemoved(removePosition); // 4. 恢复动画并滚回原位置 recyclerView.getItemAnimator().setSupportsChangeAnimations(true); layoutManager.scrollToPositionWithOffset(firstVisiblePos, topOffset);
注意:notifyItemRemoved的参数必须是移除前的条目索引,不要用移除后的列表长度计算,否则会出现索引越界或通知错误。
二、无需禁用动画的滚动恢复方案
如果不想关闭动画,也可以在通知变更后强制将列表滚回原位置,动画仍会保留,但滚动偏移会被修正:
// 记录滚动位置 LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); int targetPos = layoutManager.findFirstVisibleItemPosition(); View targetView = layoutManager.findViewByPosition(targetPos); int offsetTop = targetView != null ? targetView.getTop() : 0; // 移除条目并通知 int removePos = homeItems.size() - 1; homeItems.remove(removePos); yourAdapter.notifyItemRemoved(removePos); // 强制滚回原位置(post确保布局完成后执行) recyclerView.post(() -> layoutManager.scrollToPositionWithOffset(targetPos, offsetTop));
三、替代的单元素变更方案
如果业务允许,也可以通过以下方式实现无滚动偏移的条目移除:
- 标记条目状态而非真正移除:如果是分页加载的"加载更多"条目,可以将其设置为隐藏状态,然后调用
yourAdapter.notifyItemChanged(removePosition),这种方式不会触发布局重排动画,自然不会滚动。 - 使用
notifyItemRangeChanged:如果移除条目后,后续条目位置仅发生偏移,可调用yourAdapter.notifyItemRangeChanged(removePosition, homeItems.size() - removePosition),但这种方式本质是刷新范围内的条目,性能略逊于notifyItemRemoved,但不会引发异常滚动。
内容的提问来源于stack exchange,提问作者Kratos
相关产品推荐
相关产品推荐

