Steve
Steve

Reputation: 103

How to save scroll state of a Recyclerview when an item is clicked?

I have an issue with Recyclerview item selection , which is set up in a fragment , the problem is each page which is created by ViewVager has its own instance of the Recyclerview so the output is that selecting Recyclerview items will reset the scroll state of the Recyclerview, so I'm looking for a solution to to save scroll state of a Recyclerview when an item is clicked.

Fragment onViewCreated

// setting RecyclerView
            mEpisodesList = (CustomRecyclerView) view.findViewById(R.id.episodesLIST);
    
    
            // getting episodeslist
            ArrayList<PlanetModel> episodeslist = new ArrayList<>();
    
            for (TvShowEpisode e : mEpisodes) {
                episodeslist.add(new PlanetModel(e.mEpisode));
            }
    
    
            // Setting LinearLayoutManager
            LinearLayoutManager layoutManager
                    = new LinearLayoutManager(mContext.getApplicationContext(), LinearLayoutManager.HORIZONTAL, false);
            //mEpisodesList.setLayoutManager(new LinearLayoutManager(mContext));
            mEpisodesList.setLayoutManager(layoutManager);
    
    
            // Setting RecyclerView Adapter
            int currentPosition = getArguments().getInt("position");
            planetAdapter = new PlanetAdapter(episodeslist, currentPosition, new PlanetAdapter.OnItemClickListener() {
                @Override
                public void onItemClick(final int pos) {
                    int scrollValue = mEpisodesList.getHorizontalScrollOffset();
                    mCallback.sendText(pos, scrollValue);
                }
            });
            mEpisodesList.setAdapter(planetAdapter);
    
            int scrollValue = getArguments().getInt("scrollValue");
            new Handler().postDelayed(() -> mEpisodesList.scrollBy(scrollValue, 0), 100);

activity

    public class TvShowEpisodeDetails extends MizActivity implements TvShowEpisodeDetailsFragment.TextClicked {
    
    
        @Override
        protected int getLayoutResource() {
            return R.layout.viewpager_with_toolbar_overlay;
        }
    
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            mBus = MizuuApplication.getBus();
            super.onCreate(savedInstanceState);
    
            // Set theme
            setTheme(R.style.Mizuu_Theme_NoBackground);
    
            ViewUtils.setupWindowFlagsForStatusbarOverlay(getWindow(), true);
    
            ViewUtils.setProperToolbarSize(this, mToolbar);
    
            mShowId = getIntent().getExtras().getString(SHOW_ID);
            mSeason = getIntent().getExtras().getInt("season");
            mEpisode = getIntent().getExtras().getInt("episode");
    
            mDatabaseHelper = MizuuApplication.getTvEpisodeDbAdapter();
    
            Cursor cursor = mDatabaseHelper.getEpisodes(mShowId);
            try {
                while (cursor.moveToNext()) {
                    mEpisodes.add(new TvShowEpisode(this, mShowId,
                            cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_EPISODE_TITLE)),
                            cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_EPISODE_PLOT)),
                            cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_SEASON)),
                            cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_EPISODE)),
                            cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_EPISODE_AIRDATE)),
                            cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_EPISODE_DIRECTOR)),
                            cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_EPISODE_WRITER)),
                            cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_EPISODE_GUESTSTARS)),
                            cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_EPISODE_RATING)),
                            cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_HAS_WATCHED)),
                            cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_FAVOURITE))
                    ));
                }
            } catch (Exception e) {
            } finally {
                cursor.close();
            }
    
    
            final ArrayList<PlanetModel> episodeslist = new ArrayList<>();
    
            for (TvShowEpisode e : mEpisodes) {
                episodeslist.add(new PlanetModel(e.mEpisode));
            }
    
            mShowTitle = MizuuApplication.getTvDbAdapter().getShowTitle(mShowId);
            setTitle(mShowTitle);
    
            mViewPager = (ViewPager) findViewById(R.id.awesomepager);
            mViewPager.setAdapter(new TvShowEpisodeDetailsAdapter(getSupportFragmentManager()));
    
            for (int i = 0; i < mEpisodes.size(); i++)
                fragments.add(TvShowEpisodeDetailsFragment
                        .newInstance(mShowId, Integer.parseInt(mEpisodes.get(i).getSeason()), Integer.parseInt(mEpisodes.get(i).getEpisode()), i, mScrollValue));
    
            mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
                @Override
                public void onPageSelected(int position) {
                    for (int i = 0; i < episodeslist.size(); i++) {
                        episodeslist.get(i).setPlanetSelected(false);
                    }
                    episodeslist.get(position).setPlanetSelected(true);
                    //notify your recycler views adaper
                    ViewUtils.updateToolbarBackground(TvShowEpisodeDetails.this, mToolbar, 0, mEpisodes.get(position).getTitle(), Color.TRANSPARENT);
    
    
                }
            });
    
            if (savedInstanceState != null) {
                mViewPager.setCurrentItem(savedInstanceState.getInt("tab", 0));
            } else {
                for (int i = 0; i < mEpisodes.size(); i++) {
                    if (mEpisodes.get(i).getSeason().equals(MizLib.addIndexZero(mSeason)) && mEpisodes.get(i).getEpisode().equals(MizLib.addIndexZero(mEpisode))) {
                        mViewPager.setCurrentItem(i);
                        SharedPreferences setPref = this.getSharedPreferences("TvShowEpisodeDetails", Context.MODE_PRIVATE);
                        setPref.edit().putInt("i", i).apply();
                        break;
                    }
                }
            }
        }
    
        
    
        private class TvShowEpisodeDetailsAdapter extends FragmentPagerAdapter {
    
            public TvShowEpisodeDetailsAdapter(FragmentManager fm) {
                super(fm);
            }
    
            @Override
            public Fragment getItem(int index) {
    //            return TvShowEpisodeDetailsFragment.newInstance(mShowId, Integer.parseInt(mEpisodes.get(index).getSeason()), Integer.parseInt(mEpisodes.get(index).getEpisode()));
    
                return fragments.get(index);
            }
    
            @Override
            public int getCount() {
                return mEpisodes.size();
            }
        }

Recyclerview adapter

public class PlanetAdapter extends RecyclerView.Adapter<PlanetAdapter.PlanetViewHolder> {

    public interface OnItemClickListener {
        void onItemClick(int item);
    }

    private final ArrayList<PlanetModel> episodeslist;
    private final OnItemClickListener listener;
    SharedPreferences getPref = getContext().getSharedPreferences("TvShowEpisodeDetails", Context.MODE_PRIVATE);
    int pos = getPref.getInt("i", 0);

    int isPlanetSelected = pos;

    private final int highlightedPos;
    public PlanetAdapter(ArrayList<PlanetModel> episodeslist, int highlightedPosition, OnItemClickListener listener) {
        this.episodeslist = episodeslist;
        this.listener = listener;
        this.highlightedPos = highlightedPosition;
    }

    @NonNull
    @Override
    public PlanetAdapter.PlanetViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.planet_row, parent, false);
        return new PlanetViewHolder(v);
    }

    @Override
    public void onBindViewHolder(PlanetAdapter.PlanetViewHolder vh, final int position) {
        TextView tv = (TextView) vh.itemView;
        PlanetModel planetModel = episodeslist.get(position);
        tv.setText(planetModel.getPlanetName());
        tv.setCompoundDrawablesWithIntrinsicBounds(R.drawable.bg, 0, 0, 0);

        if (highlightedPos == position) {
            vh.itemView.setBackgroundColor(getContext().getResources().getColor(R.color.colorPrimaryLight));

        } else {
            vh.itemView.setBackgroundColor(getContext().getResources().getColor(R.color.colorPrimaryDark));
        }

//holder.image.setImageResource(R.drawable.planetimage);
//vh.text.setText(episodeslist.get(position).toString());
    }

    @Override
    public int getItemCount() {
        return episodeslist.size();
    }

    public class PlanetViewHolder extends RecyclerView.ViewHolder {

        protected TextView text;

        public PlanetViewHolder(View itemView) {
            super(itemView);
            text = (TextView) itemView.findViewById(R.id.text_id);

            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Log.d("LOG_TAG", "onClick: current item: " + highlightedPos);
                    final int previousItem = isPlanetSelected;
                    isPlanetSelected = getPosition();
                    SharedPreferences setPref = v.getContext().getSharedPreferences("PlanetAdapter", Context.MODE_PRIVATE);
                    setPref.edit().putInt("newPosition", getPosition()).apply();
                    listener.onItemClick(getPosition());
                }
            });

        }

// public void bind(final PlanetModel item, final OnItemClickListener listener) {
// }
    }

Upvotes: 1

Views: 988

Answers (2)

HX L
HX L

Reputation: 21

try this

// save
recyclerViewState = binding.mainList.layoutManager?.onSaveInstanceState()

// restore
recyclerViewState?.let {
    binding.mainList.layoutManager?.onRestoreInstanceState(it)
}

Upvotes: 2

Zain
Zain

Reputation: 40878

You can solve this by tracking the current scroll value of the RecyclerView, and whenever you hit an a ReyclerView item; add a new parameter to the listener callback with this tracked scroll value to update the new fragment that will be shown on the ViewPager.

Track the scroll value:

    mEpisodesList.setOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            scrollValue += dx;
        }
    });

Pass it as interface callback:

    planetAdapter = new PlanetAdapter(episodeslist, currentPosition, new PlanetAdapter.OnItemClickListener() {
        @Override
        public void onItemClick(final int pos) {
            mCallback.sendText(pos, scrollValue);
        }
    });

And update that in the list of ViewPager fragments before scrolling to the new page:

@Override
public void sendText(int position, int scrollValue) {
    mScrollValue = scrollValue;
    TvShowEpisodeDetailsFragment frag = fragments.get(position);
    Bundle arguments = frag.getArguments();
    arguments.putInt("scrollValue", scrollValue);
    mViewPager.setCurrentItem(position, false);
}

Upvotes: 1

Related Questions