返回
重生:让 RecyclerView 找回它遗失的滚动信息
Android
2023-10-05 10:14:20
现象
RecyclerView 是 Android 中强大的列表视图,它可以高效地处理大量数据。但在某些情况下,RecyclerView 可能会丢失滚动位置。例如,当 Activity/Fragment 被重新创建时,RecyclerView 就可能会丢失它之前的滚动位置信息。
问题根源
通常,RecyclerView 丢失滚动位置的原因是由于异步加载 Adapter 数据。当数据在 RecyclerView 需要进行布局的时候尚未加载完成,RecyclerView 就无法恢复到上次的滚动位置。
解决方案
为了解决 RecyclerView 丢失滚动位置的问题,我们可以使用以下几种方法:
- 使用
setLayoutManagerState()
和getLayoutManagerState()
方法
这种方法是在 Activity/Fragment 被销毁之前保存 RecyclerView 的布局状态,然后在 Activity/Fragment 被重新创建后恢复布局状态。
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable("layoutManagerState", recyclerView.getLayoutManager().onSaveInstanceState());
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Parcelable layoutManagerState = savedInstanceState.getParcelable("layoutManagerState");
recyclerView.getLayoutManager().onRestoreInstanceState(layoutManagerState);
}
- 使用
addOnScrollListener()
方法
这种方法是在 RecyclerView 上添加一个滚动监听器,当 RecyclerView 滚动时,滚动监听器会记录当前的滚动位置。当 Activity/Fragment 被重新创建后,滚动监听器会将记录的滚动位置恢复到 RecyclerView。
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int firstVisibleItemPosition = recyclerView.getChildAdapterPosition(recyclerView.getChildAt(0));
int firstVisibleItemOffset = recyclerView.getChildAt(0).getTop();
mLayoutManagerState.put("firstVisibleItemPosition", firstVisibleItemPosition);
mLayoutManagerState.put("firstVisibleItemOffset", firstVisibleItemOffset);
}
});
- 使用
ItemTouchHelper
类
ItemTouchHelper 是一个帮助 RecyclerView 处理条目拖拽和滑动的类。我们可以使用 ItemTouchHelper
类来保存 RecyclerView 的滚动位置。
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() {
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
}
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
if (actionState == ItemTouchHelper.ACTION_STATE_IDLE) {
int firstVisibleItemPosition = recyclerView.getChildAdapterPosition(recyclerView.getChildAt(0));
int firstVisibleItemOffset = recyclerView.getChildAt(0).getTop();
mLayoutManagerState.put("firstVisibleItemPosition", firstVisibleItemPosition);
mLayoutManagerState.put("firstVisibleItemOffset", firstVisibleItemOffset);
}
}
});
itemTouchHelper.attachToRecyclerView(recyclerView);
总结
以上三种方法都可以解决 RecyclerView 丢失滚动位置的问题。开发者可以根据自己的需要选择合适的方法。
除了以上方法之外,我们还可以通过以下方法来防止 RecyclerView 丢失滚动位置:
- 避免在 RecyclerView 中使用异步加载数据。
- 如果必须使用异步加载数据,请在数据加载完成之前禁用 RecyclerView 的滚动。
- 使用
setNestedScrollingEnabled(false)
方法来禁用 RecyclerView 的嵌套滚动。
希望本文对您有所帮助。