Skip to content

Instantly share code, notes, and snippets.

@FrantisekGazo
Last active November 10, 2024 22:57
Show Gist options
  • Save FrantisekGazo/a9cc4e18cee42199a287 to your computer and use it in GitHub Desktop.
Save FrantisekGazo/a9cc4e18cee42199a287 to your computer and use it in GitHub Desktop.
Retain & restore recycler view scroll position
package eu.f3rog.ui.custom;
import android.content.Context;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
/**
* Class {@link StatefulRecyclerView} extends {@link RecyclerView} and adds position management on configuration changes.
*
* @author FrantisekGazo
* @version 2016-03-15
*/
public final class StatefulRecyclerView
extends RecyclerView {
private static final String SAVED_SUPER_STATE = "super-state";
private static final String SAVED_LAYOUT_MANAGER = "layout-manager-state";
private Parcelable mLayoutManagerSavedState;
public StatefulRecyclerView(Context context) {
super(context);
}
public StatefulRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public StatefulRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected Parcelable onSaveInstanceState() {
Bundle bundle = new Bundle();
bundle.putParcelable(SAVED_SUPER_STATE, super.onSaveInstanceState());
bundle.putParcelable(SAVED_LAYOUT_MANAGER, this.getLayoutManager().onSaveInstanceState());
return bundle;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (state instanceof Bundle) {
Bundle bundle = (Bundle) state;
mLayoutManagerSavedState = bundle.getParcelable(SAVED_LAYOUT_MANAGER);
state = bundle.getParcelable(SAVED_SUPER_STATE);
}
super.onRestoreInstanceState(state);
}
/**
* Restores scroll position after configuration change.
* <p>
* <b>NOTE:</b> Must be called after adapter has been set.
*/
private void restorePosition() {
if (mLayoutManagerSavedState != null) {
this.getLayoutManager().onRestoreInstanceState(mLayoutManagerSavedState);
mLayoutManagerSavedState = null;
}
}
@Override
public void setAdapter(Adapter adapter) {
super.setAdapter(adapter);
restorePosition();
}
}
@jrm-d
Copy link

jrm-d commented Apr 11, 2018

Hello ! It works perfectly, thanks a lot.
For people asking how to use it: import the file in your project, and just declare your StatefulRecyclerview in your layout files instead of the native "android.support.v7.widget.RecyclerView"

@jwhijazi
Copy link

Error inflating class StatefulRecyclerView

@tusharpingale04
Copy link

Thanks for the code. It's Working!

@MahmoudiOussama
Copy link

MahmoudiOussama commented Apr 8, 2019

Thanks a lot.
Working for me too, tested it on Android 6, 8 and 9 devices.

@backupalisher
Copy link

How to use this one? Please tell me an example

@FrantisekGazo
Copy link
Author

The usage is as @jrm-d wrote:

For people asking how to use it: import the file in your project, and just declare your StatefulRecyclerview in your layout files instead of the native "android.support.v7.widget.RecyclerView"

But I didn't use it in a long time (3 years old snippet)

@backupalisher
Copy link

Error inflating class StatefulRecyclerView

@sobhansarfi
Copy link

How to use this code?
Please explain a full person or send an example

@sobhansarfi
Copy link

Thank you for the code, this works inside fragment 👍 , but not working inside activity 👎
How to use this code?
Please explain a full person or send an example

@chriskikoti
Copy link

Worked fine. Thanks

@chieuancucbo
Copy link

If you are looking for a solution, don't do like that, you will never know how to use the code.

Now do like this:
All below code you put in the activity (where you using the Recyclerview)

// save position:
RecyclerView rcv = findViewById(.....);
rcv.setAdapter(....);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
rcv.setLayoutManager(layoutManager);

rcv.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                pos = layoutManager.findFirstVisibleItemPosition();
               // everytime you scroll the list, new position will be saved in app's data storage:
                SharedPreferences preferences = getSharedPreferences("anyname", MODE_PRIVATE);
                SharedPreferences.Editor editor = preferences.edit();
                editor.putInt("KEY_LAST_POSITION", pos).apply();
            }
        });

// using position: 
SharedPreferences preferences = getSharedPreferences("anyname", MODE_PRIVATE);
int position = preferences.getInt("KEY_LAST_POSITION", 0); // 0 is the default value
rcv.scrollToPosition(position);

@MichalDanielDobrzanski
Copy link

MichalDanielDobrzanski commented Jan 18, 2022

@chieuancucbo you don't know your code. It is remembering an item position, not the exact scroll.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment