Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to save scroll position of recyclerview in fragment

I have followed so many answers from here.. but not a single one solving my issue .. that's why i am asking.

I want to save scroll position in a fragment. In So many articles they have suggested to follow

@Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
    }

and

@Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
    }

But this two method is not available in fragment.

My code:

private int mPositionIng = RecyclerView.NO_POSITION;

private String KEY_POSITION_ING = "KeyPositionIng";

in OnCreateView()

if (savedInstanceState != null) {

            if (savedInstanceState.containsKey(KEY_POSITION_ING)) {
                mPositionIng = savedInstanceState.getInt(KEY_POSITION_ING);
            }
}

Override Methods in fragment They are not same method as above. i don't know where i am doing wrong.

@Override
    public void onSaveInstanceState(Bundle outState) {

        int scrollPositionIng = mRecyclerViewIngredients.computeVerticalScrollOffset();

        mPositionIng = scrollPositionIng;

        outState.putInt(KEY_POSITION_ING, mPositionIng);
        super.onSaveInstanceState(outState);
    }

@Override
    public void onViewStateRestored(@Nullable Bundle savedInstanceState) {

        if (mPositionIng != RecyclerView.NO_POSITION) {

            mRecyclerViewIngredients.getLayoutManager().scrollToPosition(mPositionIng);
        }


        super.onViewStateRestored(savedInstanceState);
    }

I just need to save scroll position while the orientation changes .. Please help. Any Suggestion will be help full. Thanks......

like image 667
Tapan Kumar Patro Avatar asked Jul 26 '17 02:07

Tapan Kumar Patro


People also ask

Can I scroll RecyclerView?

To be able to scroll through a vertical list of items that is longer than the screen, you need to add a vertical scrollbar. Inside RecyclerView , add an android:scrollbars attribute set to vertical .

Can you put RecyclerView in fragment?

To Implement recyclerview in fragment, Create a Blank fragment on which we want to implement recyclerview. and give it name NewFragment. To create Recyclerview with cardview we need to add two dependencies in build. gradle file.

How do I stop refreshing RecyclerView data scroll to top position android?

Make a setDataList method in your adapter class. And set your updated list to adapter list. And then every time of calling API set that list to setDataList and call adapter. notifyDataSetChanged() method of your adapter class.


2 Answers

Update

Everything I wrote below is correct, but the reason it didn't work for you is that I didn't realize how your Activity's layout was structured. Here is your Activity's layout (slightly cleaned up):

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.tapan.recipemaster.activity.RecipeDetailActivity">
    
        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
    
                <FrameLayout
                    android:id="@+id/fl_fragment_detail"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:padding="@dimen/padding_10dp"/>
    
            </RelativeLayout>
    
        </ScrollView>
    
    </android.support.constraint.ConstraintLayout>

Meanwhile, this is your Fragment's layout (again, slightly cleaned up):

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.tapan.recipemaster.fragment.RecipeDetailFragment">

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="@dimen/padding_10dp"
            android:orientation="vertical">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@color/colorAccent"
                android:orientation="vertical">

                <TextView
                    android:id="@+id/tv_ingredient"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:textColor="#FFF"
                    android:textSize="@dimen/text_23sp"
                    android:text="Ingredients"/>

                <android.support.v7.widget.RecyclerView
                    android:id="@+id/rv_ingredients"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="@dimen/dimen_8dp"/>

            </LinearLayout>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical">

                <TextView
                    android:id="@+id/tv_step"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="@dimen/dimen_8dp"
                    android:textColor="@color/colorPrimaryDark"
                    android:textSize="@dimen/text_23sp"
                    android:text="Steps"/>

                <android.support.v7.widget.RecyclerView
                    android:id="@+id/rv_steps"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="@dimen/dimen_8dp"/>

            </LinearLayout>

        </LinearLayout>

    </ScrollView>

</FrameLayout>

Both RecyclerViews have android:layout_height="wrap_content", which means they do not scroll. Rather, the ScrollView in your Activity is the view providing the scrolling behavior, so it is this view whose scroll position must be saved.

You can have the system do this for you by giving this ScrollView an id. Any id you want, as long as it's unique. You don't have to write any Java at all.

<ScrollView
    android:id="@+id/thisfixestheproblem"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

Make sure you're modifying the ScrollView in your activity's layout, not the one in your fragment's layout.

Original

None of the code you posted should be necessary to save your RecyclerView's scroll position on orientation change. As long as the RecyclerView has a unique ID in your layout, it will save the scroll position for you automatically.

Here is a very small sample app that shows automatic saving of scroll position, even with a dynamically added Fragment. As you can see, the only instance state I'm saving myself is whether the button to start the fragment should be visible.

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private Button button;

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putBoolean("buttonVisible", button.getVisibility() == View.VISIBLE);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                getSupportFragmentManager()
                        .beginTransaction()
                        .replace(R.id.content, new MyFragment())
                        .commit();

                button.setVisibility(View.GONE);
            }
        });

        if (savedInstanceState != null) {
            boolean buttonVisible = savedInstanceState.getBoolean("buttonVisible");
            button.setVisibility(buttonVisible ? View.VISIBLE : View.GONE);
        }
    }
}

MyFragment.java

public class MyFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.myfragment, container, false);

        RecyclerView recycler = (RecyclerView) root.findViewById(R.id.recycler);
        recycler.setAdapter(new MyAdapter());

        return root;
    }

    private static class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {

        @Override
        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            LayoutInflater inflater = LayoutInflater.from(parent.getContext());
            View itemView = inflater.inflate(R.layout.itemview, parent, false);
            return new MyViewHolder(itemView);
        }

        @Override
        public void onBindViewHolder(MyViewHolder holder, int position) {
            Drawable d = new ColorDrawable(Color.argb(0xff, 0, 0, position));
            ViewCompat.setBackground(holder.image, d);
            holder.text.setText("" + position);
        }

        @Override
        public int getItemCount() {
            return 256;
        }
    }

    private static class MyViewHolder extends RecyclerView.ViewHolder {

        final View image;
        final TextView text;

        MyViewHolder(View itemView) {
            super(itemView);

            this.image = itemView.findViewById(R.id.image);
            this.text = (TextView) itemView.findViewById(R.id.text);
        }
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/content"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="create fragment"/>

</FrameLayout>

myfragment.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/recycler"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layoutManager="android.support.v7.widget.LinearLayoutManager"
    tools:listitem="@layout/itemview"/>

itemview.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center_vertical"
    android:orientation="horizontal">

    <View
        android:id="@+id/image"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_margin="12dp"
        tools:background="#333"/>

    <TextView
        android:id="@+id/text"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        tools:text="text"/>

</LinearLayout>
like image 134
Ben P. Avatar answered Nov 08 '22 06:11

Ben P.


Let the Android OS handle that for you, in AndroidManifest.xml inside your wanted tag activity add:

android:configChanges="orientation|screenSize"
like image 1
MohammadL Avatar answered Nov 08 '22 07:11

MohammadL