Как сохранить позицию прокрутки RecyclerView с помощью RecyclerView.Государство?
У меня есть вопрос о Android RecyclerView.Государство.
Я использую RecyclerView, как я могу использовать и связать его с RecyclerView.Государство?
моя цель -сохранить позицию прокрутки RecyclerView.
10 ответов
как вы планируете сохранить последнюю сохраненную позицию с RecyclerView.State
?
вы всегда можете положиться на хорошее состояние сохранения. Продлить RecyclerView
и переопределить данные метода onsaveinstance() и onRestoreInstanceState()
:
@Override
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
LayoutManager layoutManager = getLayoutManager();
if(layoutManager != null && layoutManager instanceof LinearLayoutManager){
mScrollPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
}
SavedState newState = new SavedState(superState);
newState.mScrollPosition = mScrollPosition;
return newState;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
super.onRestoreInstanceState(state);
if(state != null && state instanceof SavedState){
mScrollPosition = ((SavedState) state).mScrollPosition;
LayoutManager layoutManager = getLayoutManager();
if(layoutManager != null){
int count = layoutManager.getChildCount();
if(mScrollPosition != RecyclerView.NO_POSITION && mScrollPosition < count){
layoutManager.scrollToPosition(mScrollPosition);
}
}
}
}
static class SavedState extends android.view.View.BaseSavedState {
public int mScrollPosition;
SavedState(Parcel in) {
super(in);
mScrollPosition = in.readInt();
}
SavedState(Parcelable superState) {
super(superState);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeInt(mScrollPosition);
}
public static final Parcelable.Creator<SavedState> CREATOR
= new Parcelable.Creator<SavedState>() {
@Override
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
@Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
если вы используете LinearLayoutManager, он поставляется с предварительно построенным api сохранения linearLayoutManagerInstance.данные метода onsaveinstance() и восстановить api linearLayoutManagerInstance.onRestoreInstanceState(...)
С этим вы можете сохранить возвращенный parcelable в свой штат. например,
outState.putParcelable("KeyForLayoutManagerState", linearLayoutManagerInstance.onSaveInstanceState());
, и восстановить положение с состоянием сохранен. е.г,
Parcelable state = savedInstanceState.getParcelable("KeyForLayoutManagerState");
linearLayoutManagerInstance.onRestoreInstanceState(state);
чтобы завернуть все, ваш окончательный код будет выглядеть что-то как
private static final String BUNDLE_RECYCLER_LAYOUT = "classname.recycler.layout";
/**
* This is a method for Fragment.
* You can do the same in onCreate or onRestoreInstanceState
*/
@Override
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
if(savedInstanceState != null)
{
Parcelable savedRecyclerLayoutState = savedInstanceState.getParcelable(BUNDLE_RECYCLER_LAYOUT);
recyclerView.getLayoutManager().onRestoreInstanceState(savedRecyclerLayoutState);
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(BUNDLE_RECYCLER_LAYOUT, recyclerView.getLayoutManager().onSaveInstanceState());
}
Edit: вы также можете использовать те же API с GridLayoutManager, так как это подкласс LinearLayoutManager. Спасибо @wegsehen за предложение.
Edit: помните, что если вы также загружаете данные в фоновом потоке, вам нужно будет вызвать onRestoreInstanceState в вашем методе onPostExecute/onLoadFinished для восстановления позиции при изменении ориентации, например
@Override
protected void onPostExecute(ArrayList<Movie> movies) {
mLoadingIndicator.setVisibility(View.INVISIBLE);
if (movies != null) {
showMoviePosterDataView();
mDataAdapter.setMovies(movies);
mRecyclerView.getLayoutManager().onRestoreInstanceState(mSavedRecyclerLayoutState);
} else {
showErrorMessage();
}
}
магазине
lastFirstVisiblePosition = ((LinearLayoutManager)rv.getLayoutManager()).findFirstCompletelyVisibleItemPosition();
восстановить
((LinearLayoutManager) rv.getLayoutManager()).scrollToPosition(lastFirstVisiblePosition);
и если это не сработает, попробуй
((LinearLayoutManager) rv.getLayoutManager()).scrollToPositionWithOffset(lastFirstVisiblePosition,0)
ставлю магазину в onPause()
и восстановить в onResume()
Я устанавливаю переменные в onCreate (), сохраняю позицию прокрутки в onPause () и устанавливаю позицию прокрутки в onResume ()
public static int index = -1;
public static int top = -1;
LinearLayoutManager mLayoutManager;
@Override
public void onCreate(Bundle savedInstanceState)
{
//Set Variables
super.onCreate(savedInstanceState);
cRecyclerView = ( RecyclerView )findViewById(R.id.conv_recycler);
mLayoutManager = new LinearLayoutManager(this);
cRecyclerView.setHasFixedSize(true);
cRecyclerView.setLayoutManager(mLayoutManager);
}
@Override
public void onPause()
{
super.onPause();
//read current recyclerview position
index = mLayoutManager.findFirstVisibleItemPosition();
View v = cRecyclerView.getChildAt(0);
top = (v == null) ? 0 : (v.getTop() - cRecyclerView.getPaddingTop());
}
@Override
public void onResume()
{
super.onResume();
//set recyclerview position
if(index != -1)
{
mLayoutManager.scrollToPositionWithOffset( index, top);
}
}
Я хотел сохранить положение прокрутки Recycler View при навигации от моей активности списка, а затем нажав кнопку "назад", чтобы вернуться. Многие из решений, предусмотренных для этой проблемы, были либо намного сложнее, чем нужно, либо не работали для моей конфигурации, поэтому я решил поделиться своим решением.
сначала сохраните состояние экземпляра в onPause, как показали многие. Я думаю, что здесь стоит подчеркнуть, что эта версия onSaveInstanceState является методом из RecyclerView.Класс LayoutManager выполняет.
private LinearLayoutManager mLayoutManager;
Parcelable state;
@Override
public void onPause() {
super.onPause();
state = mLayoutManager.onSaveInstanceState();
}
ключ к правильной работе - убедиться, что вы вызываете onRestoreInstanceState после подключения адаптера, как указано в других потоках. Однако фактический вызов метода намного проще, чем многие указали.
private void someMethod() {
mVenueRecyclerView.setAdapter(mVenueAdapter);
mLayoutManager.onRestoreInstanceState(state);
}
вам не нужно сохранять и восстанавливать состояние самостоятельно. Если вы установили уникальный идентификатор в xml и recyclerView.setSaveEnabled (true) (true по умолчанию) система сделает это автоматически. Вот еще об этом:http://trickyandroid.com/saving-android-view-state-correctly/
вот как я восстанавливаю позицию RecyclerView с GridLayoutManager после вращения, когда вам нужно перезагрузить данные из интернета с помощью AsyncTaskLoader.
сделайте глобальную переменную Parcelable и GridLayoutManager и статическую конечную строку:
private Parcelable savedRecyclerLayoutState;
private GridLayoutManager mGridLayoutManager;
private static final String BUNDLE_RECYCLER_LAYOUT = "recycler_layout";
сохранить состояние gridLayoutManager в onSaveInstance ()
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(BUNDLE_RECYCLER_LAYOUT,
mGridLayoutManager.onSaveInstanceState());
}
восстановить в onRestoreInstanceState
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
//restore recycler view at same position
if (savedInstanceState != null) {
savedRecyclerLayoutState = savedInstanceState.getParcelable(BUNDLE_RECYCLER_LAYOUT);
}
}
затем, когда загрузчик извлекает данные из интернета, вы восстанавливаете recyclerview положение в onLoadFinished()
if(savedRecyclerLayoutState!=null){
mGridLayoutManager.onRestoreInstanceState(savedRecyclerLayoutState);
}
..конечно, вам нужно создать экземпляр gridLayoutManager внутри onCreate. Ура!--5-->
для меня проблема заключалась в том, что я настраивал новый layoutmanager каждый раз, когда я менял свой адаптер, теряя позицию прокрутки que на recyclerView.
вот мой подход, чтобы сохранить их и поддерживать состояние recyclerview во фрагменте. Во-первых, добавьте изменения конфигурации в родительское действие, как показано ниже кода.
android:configChanges="orientation|screenSize"
затем в вашем фрагменте объявите этот метод экземпляра
private Bundle mBundleRecyclerViewState;
private Parcelable mListState = null;
private LinearLayoutManager mLinearLayoutManager;
добавить ниже код в метод @onPause
@Override
public void onPause() {
super.onPause();
//This used to store the state of recycler view
mBundleRecyclerViewState = new Bundle();
mListState =mTrailersRecyclerView.getLayoutManager().onSaveInstanceState();
mBundleRecyclerViewState.putParcelable(getResources().getString(R.string.recycler_scroll_position_key), mListState);
}
добавить метод onConfigartionChanged, как показано ниже.
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
//When orientation is changed then grid column count is also changed so get every time
Log.e(TAG, "onConfigurationChanged: " );
if (mBundleRecyclerViewState != null) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mListState = mBundleRecyclerViewState.getParcelable(getResources().getString(R.string.recycler_scroll_position_key));
mTrailersRecyclerView.getLayoutManager().onRestoreInstanceState(mListState);
}
}, 50);
}
mTrailersRecyclerView.setLayoutManager(mLinearLayoutManager);
}
это approch будет reslove ваша проблема. если у вас есть diffrent layout manager, то просто замените верхний менеджер компоновки.
активности.java:
public RecyclerView.LayoutManager mLayoutManager;
Parcelable state;
mLayoutManager = new LinearLayoutManager(this);
// Inside `onCreate()` lifecycle method, put the below code :
if(state != null) {
mLayoutManager.onRestoreInstanceState(state);
}
@Override
protected void onResume() {
super.onResume();
if (state != null) {
mLayoutManager.onRestoreInstanceState(state);
}
}
@Override
protected void onPause() {
super.onPause();
state = mLayoutManager.onSaveInstanceState();
}
почему я использую OnSaveInstanceState()
на onPause()
означает, что при переключении на другую активность будет вызываться onPause.Он сохранит эту позицию прокрутки и восстановит позицию, когда мы вернемся из другой деятельности.