Reputation:
I have a fragment which shows a list of tv show episodes , swiping left or right will switch to the next or previous episode(this is done by ViewPager
), then I created a horizontal RecyclerView
to show the list of the episodes in a horizontal scroll bar.
Now I have 2 problems
Problem 1
For example I selected episode 9, now episode 9 is highlighted in the RecyclerView
Scroll bar then I scroll until I reach 14, 15, 17 (this is the last scroll state of 9) then I click on 14 it gets highlighted but the scroll resets to 1 (which is not what I want) , now I scroll back and I see 14 is highlighted , now when I scroll back to 9 and tap on it , the scroll state of 9 goes to the last state that I scrolled to 15 and clicked on it. Please check this video
Problem 2 For example I selected 2 now I tap on 3, it switches to 3 but the highlight is still on 2 I have to click again on 3 to get it highlighted. please take a look at this video
I think this is all caused by the fact that each episode or I should say each page of ViewPager
has its own instance of the RecyclerView
. correct me if I'm wrong
But what I want is a single instance of RecyclerView
to be available for all episodes.
How can I Fix that?
Hint
RecyclerView Adapter is set inside the fragment, transfering the index of the clicked item (episode) from the adapter to the fragment via onItemClick
interface from the adapter. From inside the fragment I use another interface sendText(int position);
to tranfer the index of the clicked item to the Activity so that I can set ViewPager mViewPager.setCurrentItem(position,false);
RecyclerView Adapter
public class PlanetAdapter extends RecyclerView.Adapter<PlanetAdapter.PlanetViewHolder> {
public interface OnItemClickListener {
void onItemClick(String item);
}
private static int lastClickedPosition = -1;
private int selectedItem;
private ArrayList<String> episodeslist;
private OnItemClickListener listener;
SharedPreferences getPref1x1 = getContext().getSharedPreferences("PlanetAdapter", Context.MODE_PRIVATE);
int pos1x1 = getPref1x1.getInt("position",0);
int selectedPosition=pos1x1;
public PlanetAdapter(ArrayList<String> episodeslist, OnItemClickListener listener) {
this.episodeslist = episodeslist;
this.listener = listener;
}
@Override
public PlanetAdapter.PlanetViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v= LayoutInflater.from(parent.getContext()).inflate(R.layout.planet_row, parent,false);
PlanetViewHolder vh=new PlanetViewHolder(v);
return vh;
}
@Override
public void onBindViewHolder(PlanetAdapter.PlanetViewHolder vh, int position) {
TextView tv = (TextView) vh.itemView;
tv.setText(episodeslist.get(position));
tv.setCompoundDrawablesWithIntrinsicBounds(R.drawable.bg, 0, 0, 0);
vh.bind(episodeslist.get(position), listener);
//if(selectedPosition==position)
// vh.itemView.setBackgroundColor(getContext().getResources().getColor(R.color.colorPrimaryLight));
//else
// vh.itemView.setBackgroundColor(getContext().getResources().getColor(R.color.colorPrimaryDark));
vh.itemView.setBackgroundColor(getContext().getResources().getColor(R.color.colorPrimaryLight));
if (selectedPosition == position) {
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);
}
public void bind(final String item, final OnItemClickListener listener) {
itemView.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
int position = getPosition();
int previousItem = selectedPosition;
selectedPosition = position;
notifyItemChanged(previousItem);
notifyItemChanged(position);
//selectedPosition=position;
//notifyDataSetChanged();
SharedPreferences setPref = v.getContext().getSharedPreferences("PlanetAdapter", Context.MODE_PRIVATE);
setPref.edit().putInt("position", position).apply ();
listener.onItemClick(item);
//Toast.makeText(getContext(), "You have clicked " + item, Toast.LENGTH_SHORT).show();
//Toast.makeText(getContext(), "You have clicked " + ((TextView) itemView).getText(), Toast.LENGTH_SHORT).show();
}
});
}
}
}
The Fragment
public class TvShowEpisodeDetailsFragment extends Fragment {
TextClicked mCallback;
public interface TextClicked{
void sendText(int position);
}
// other code here
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.episode_details, container, false);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
mCallback = (TextClicked) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement TextClicked");
}
}
@Override
public void onViewCreated(final View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// other code here
// getting episodeslist
mEpisodesList = (RecyclerView) view.findViewById(R.id.episodesLIST);
ArrayList<String> episodeslist = new ArrayList<String>(mEpisodes.size()); //set initialize capacity as it's know, some negligible performance related reason
for(TvShowEpisode e : mEpisodes){
episodeslist.add(e.mEpisode);
}
// Setting LinearLayoutManager
LinearLayoutManager layoutManager
= new LinearLayoutManager(mContext.getApplicationContext(), LinearLayoutManager.HORIZONTAL, false);
//mEpisodesList.setLayoutManager(new LinearLayoutManager(mContext));
mEpisodesList.setLayoutManager(layoutManager);
// Setting RecyclerView Adapter
mEpisodesList.setAdapter(new PlanetAdapter(episodeslist, new PlanetAdapter.OnItemClickListener() {
@Override public void onItemClick(String item) {
SharedPreferences getPref = getActivity ().getSharedPreferences("PlanetAdapter", Context.MODE_PRIVATE);
int pos = getPref.getInt("position",0);
mCallback.sendText(pos);
}
}));
// other code here
}
@Override
public void onDetach() {
mCallback = null; // => avoid leaking, thanks @Deepscorn
super.onDetach();
}
// other code here
}
The activity
public class TvShowEpisodeDetails extends MizActivity implements TvShowEpisodeDetailsFragment.TextClicked{
private static final String SHOW_ID = "showId";
private ArrayList<TvShowEpisode> mEpisodes = new ArrayList<TvShowEpisode>();
private int mSeason, mEpisode;
private String mShowId, mShowTitle;
private ViewPager mViewPager;
private DbAdapterTvShowEpisodes mDatabaseHelper;
private Bus mBus;
@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();
}
mShowTitle = MizuuApplication.getTvDbAdapter().getShowTitle(mShowId);
setTitle(mShowTitle);
mViewPager = (ViewPager) findViewById(R.id.awesomepager);
mViewPager.setAdapter(new TvShowEpisodeDetailsAdapter(getSupportFragmentManager()));
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
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 setPref1x1 = getContext().getSharedPreferences("PlanetAdapter", Context.MODE_PRIVATE);
setPref1x1.edit().putInt("position", i).apply ();
break;
}
}
}
}
@Subscribe
public void onScrollChanged(TvShowEpisodeDetailsFragment.BusToolbarColorObject object) {
ViewUtils.updateToolbarBackground(this, mToolbar, object.getAlpha(),
mEpisodes.get(mViewPager.getCurrentItem()).getTitle(), object.getToolbarColor());
}
public void onResume() {
super.onResume();
mBus.register(this);
ViewUtils.updateToolbarBackground(this, mToolbar, 0, mShowTitle, Color.TRANSPARENT);
}
@Override
public void onPause() {
super.onPause();
mBus.unregister(this);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public void onStart() {
super.onStart();
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("tab", mViewPager.getCurrentItem());
}
@Override
public void sendText(int position) {
mViewPager.setCurrentItem(position,false);
//Toast.makeText(getContext(), "Item Clicked " + text, Toast.LENGTH_SHORT).show();
}
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()));
}
@Override
public int getCount() {
return mEpisodes.size();
}
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 0) {
if (resultCode == Activity.RESULT_OK) {
setResult(Activity.RESULT_OK);
finish();
}
}
}
}
Upvotes: 0
Views: 136
Reputation: 91
You have just saved the position of the selected item but not the state of all the items in the list i.e whether they are selected or unselected. Recycler View recycles the views when scrolled. So, you just need to use ArrayList of PlanelModel instead of ArrayList of String as shared below which has a variable called "isPlanetSelected" to save state of the item.
public class PlanetModel {
private String planetName;
private boolean isPlanetSelected;
public String getPlanetName() {
return planetName;
}
public void setPlanetName(String planetName) {
this.planetName = planetName;
}
public boolean isPlanetSelected() {
return isPlanetSelected;
}
public void setPlanetSelected(boolean planetSelected) {
isPlanetSelected = planetSelected;
}
}
Make following changes in your PlanetAdapter class:
ArrayList of PlanetModel instead of String:
private ArrayList<PlanetModel> episodeslist;
In onBindViewHolder set name of the episode as:
tv.setText(episodeslist.get(position).getPlanetName());
In onBindViewHolder set selected state of the view:
if (episodeslist.get(position).isPlanetSelected()) {
vh.itemView.setBackgroundColor(getContext().getResources().getColor(R.color.colorPrimaryDark));
}else{
vh.itemView.setBackgroundColor(getContext().getResources().getColor(R.color.colorPrimaryLight));
}
Also, update the isPlanetSelected for that particular index
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
for (int i=0; i<mEpisodes.length; i++)
{
mEpisodes.get(i).setIsPlanetSelected(false);
}
mEpisodes.get(position).setIsPlanetSelected(true);
//notify your recycler views adaper
}
});
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { @Override public void onPageSelected(int position) { episodeslist.get(position).setPlanetSelected(true) } });
Don't forget to set planet selected false wen it is unselected
episodeslist.get(position).setPlanetSelected(false)
Both your issues will be resolved with above approach.
Thanks.
Upvotes: 0