Как сохранить положение прокрутки RecyclerView в Android?
У меня есть вид Recycler, который лежит внутри SwipeRefreshLayout. Кроме того, есть возможность открыть каждый элемент в другой деятельности. После возвращения в Recycler мне нужно перейти к выбранному элементу или к предыдущему Y. Как это сделать?
Да, я погуглил, нашел в StackOverFlow статьи о сохранении экземпляра менеджера компоновки, как этот: RecyclerView состояние сохранения / восстановления между действиями. Но это не помогает мне.
ОБНОВИТЬ
Сейчас у меня проблема такого рода, но, конечно, она тоже не работает.
private int scrollPosition;
...//onViewCreated - it is fragment
recyclerView.setHasFixedSize(true);
LinearLayoutManager llm = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(llm);
data = new ArrayList<>();
adapter.setData(getActivity(), data);
recyclerView.setAdapter(adapter);
...
@Override
public void onResume() {
super.onResume();
recyclerView.setScrollY(scrollPosition);
}
@Override
public void onPause() {
super.onPause();
scrollPosition = recyclerView.getScrollY();
}
Да, я пробовал scrollTo(int, int) - не работает.
Теперь я попробовал просто прокрутить, например, до Y = 100, но он не прокручивается вообще.
9 ответов
Сохранить текущее состояние позиции просмотра корзины @onPause:
positionIndex= llManager.findFirstVisibleItemPosition();
View startView = rv.getChildAt(0);
topView = (startView == null) ? 0 : (startView.getTop() - rv.getPaddingTop());
Восстановите позицию прокрутки @onResume:
if (positionIndex!= -1) {
llManager.scrollToPositionWithOffset(positionIndex, topView);
}
или другой способ может быть @onPause:
long currentVisiblePosition = 0;
currentVisiblePosition = ((LinearLayoutManager)rv.getLayoutManager()).findFirstCompletelyVisibleItemPosition();
восстановить @onResume:
((LinearLayoutManager) rv.getLayoutManager()).scrollToPosition(currentVisiblePosition);
currentVisiblePosition = 0;
Многие из этих ответов кажутся слишком сложными.
LayoutManager поддерживает onRestoreInstanceState
не требует сохранения позиций прокрутки и т. д. Встроенный метод уже сохраняет идеальные позиции пикселей.
пример кода фрагмента (проверка на ноль и т. д. для ясности удалена):
private Parcelable listState;
private RecyclerView list;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
listState=savedInstanceState.getParcelable("ListState");
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable("ListState", list.getLayoutManager().onSaveInstanceState());
}
тогда просто позвони
list.getLayoutManager().onRestoreInstanceState(listState);
как только ваши данные были присоединены к вашему RecyclerView
Начиная с версии 1.2.0-alpha02 библиотеки androidx recyclerView, она теперь управляется автоматически. Просто добавьте его с помощью:
implementation "androidx.recyclerview:recyclerview:1.2.0-alpha02"
И используйте:
adapter.stateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY
Перечисление StateRestorationPolicy имеет 3 варианта:
- РАЗРЕШИТЬ - состояние по умолчанию, которое немедленно восстанавливает состояние RecyclerView на следующем проходе макета
- PREVENT_WHEN_EMPTY - восстанавливает состояние RecyclerView только тогда, когда адаптер не пустой (adapter.getItemCount() > 0). Если ваши данные загружаются асинхронно, RecyclerView ждет, пока данные будут загружены, и только после этого состояние восстанавливается. Если у вас есть элементы по умолчанию, такие как заголовки или индикаторы выполнения загрузки, как часть вашего адаптера, вы должны использовать параметр PREVENT, если элементы по умолчанию не добавлены с помощью MergeAdapter. MergeAdapter ожидает готовности всех своих адаптеров и только после этого восстанавливает состояние.
- PREVENT - все восстановление состояния откладывается до тех пор, пока вы не установите ALLOW или PREVENT_WHEN_EMPTY.
Обратите внимание, что на момент этого ответа библиотека recyclerView все еще находится в alpha03, но альфа-фаза не подходит для производственных целей.
Для получения позиции прокрутки используйте свой просмотрщик linearlayoutmanager.
int position = 0;
if (linearLayoutManager != null) {
scrollPosition = inearLayoutManager.findFirstVisibleItemPosition();
}
и при восстановлении используйте следующий код
if (linearLayoutManager != null) {
cardRecyclerView.scrollToPosition(mScrollPosition);
}
Надеюсь, это поможет вам
в методе фрагмента onSaveInstanceState() вы можете сохранить положение прокрутки RecycleView
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
LinearLayoutManager layoutManager = (LinearLayoutManager)
recyclerView.getLayoutManager();
outState.putInt("scrolled_position",
layoutManager.findFirstCompletelyVisibleItemPosition());
}
затем вы можете получить сохраненную позицию прокрутки в методе onViewStateRestored()
@Override
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
if (savedInstanceState != null) {
int scrollPosition = savedInstanceState.getInt("scrolled_position");
recyclerView.scrollToPosition(scrollPosition);
}
}
Чтобы сохранить позицию в настройках, добавьте это в свой onStop()
int currentVisiblePosition = ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstCompletelyVisibleItemPosition();
getPreferences(MODE_PRIVATE).edit().putInt("listPosition", currentVisiblePosition).apply();
затем восстановить положение, как это
if (getItemCount() == 0) {
int savedListPosition = getPreferences(MODE_PRIVATE).getInt("listPosition", 0);
recyclerView.getLayoutManager().scrollToPosition(savedListPosition); }
последний код должен быть добавлен в событие Адаптера (не уверен, что это событие ведьмы, но в моем случае это onEvent() - com.google.firebase.firestore.EventListener)
Самый простой и совместимый с переходом способ, который я нашел:
@Override
public void onPause() {
super.onPause();
recyclerView.setLayoutFrozen(true);
}
@Override
public void onResume() {
super.onResume();
recyclerView.setLayoutFrozen(false);
}
По некоторым причинам есть много вводящих в заблуждение советов / предложений о том, как сохранить и восстановить позицию прокрутки в your_scrolling_container при изменении ориентации.
Возьмите текущую позицию прокрутки и сохраните ее в onSaveInstanceState Activity. Расширение определенного прокручиваемого представления, чтобы сделать то же самое там. Предотвращение разрушения Activity при вращении. И да, они работают нормально, но…
Но на самом деле все гораздо проще, потому что Android уже делает это за вас!
Если вы внимательно посмотрите на источники RecyclerView/ListView/ScrollView/NestedScrollView, вы увидите, что каждый из них сохраняет свою позицию прокрутки в onSaveInstanceState. И во время первого прохода макета они пытаются прокрутить до этой позиции в методе onLayout.
Есть только 2 вещи, которые нужно сделать, чтобы убедиться, что все будет работать нормально:
Установите идентификатор для вашего прокручиваемого представления, что, вероятно, уже сделано. В противном случае Android не сможет автоматически сохранить состояние просмотра.
Предоставьте данные перед первым проходом макета, чтобы иметь те же границы прокрутки, которые были до вращения. На этом этапе у разработчиков обычно возникают некоторые проблемы.
Ты можешь использовать scrollToPosition
или же smoothScrollToPosition
для прокрутки до любой позиции элемента в RecyclerView.
Если вы хотите прокрутить до позиции элемента в адаптере, то вам придется использовать адаптеры scrollToPosition
или же smoothScrollToPosition
,