Similar question have been asked, but i can't get any of them work.
What i want is to select item in RecyclerView, change the background of that item view, and store the position of item selected.
The main problem is that you have onCreateViewHolder (in adapter), onBindViewHolder (in adapter) and ViewHolder constructor and everybody is working with different methods. Now, i don't even know where to put onClickListener (in previous projects i've put it in ViewHolder), because people are suggesting the other two methods too.
My idea was to store each ViewHolder (or View) in list, so i can have reference to each row, and change the background from there. But that didn't work for me, because when i try to add to list of View(or ViewHolders), from any of three places (onCreateVH, onBindVH, VH class), my app crashes for some reason (null pointer ex).
Any suggestions? Where and how to implement it?
Pretty much every single app has a list of something they want to display. RecyclerView Selection is a library that will allow you to handle item selection a lot easier. It will help you handle motion events and touch events, and convert them into selection in the RecyclerView.
setHasStableIds is an optimization hint that you can give to the recycler. You're telling it "when I provide a ViewHolder , its id is unique and will not change." It's very easy to write an Adapter that does otherwise - for example, linking the id to item position.
Make global variable to store position and handle click listener in ViewHolder
. Onclick
of item, change the global position value like
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
globalPosition=getAdapterPosition();
notifyDataSetChanged();
}
});
then in onBindViewHolder
if(postion==globalPosition)
{
//change color like
textview.setTextColor(Color.RED);
}
else
{
//revert back to regular color
textview.setTextColor(Color.WHITE);
}
with this code, the item you clicked get red colored and all other wiil be in white.
First of all, you asked where to put the onClickListener - you should put it in the onBindViewHolder. You can also attach a onClickListener in the ViewHolder class of your item like so:
public class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
}
}
As to implementing a single selection behaviour, the answers given here work but calling onNotifyDatasetChanged is bad for performance if you have a lot of items as it rebinds all views from scratch each time.
The link given by denvercoder9 is a good tutorial to understand a lot of things about setting up RecyclerView, but I think it makes single selection behaviour complicated. I am going to answer comprehensively giving everything one might need to make it work. Here's how I implemented the single selection behaviour:
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
final YourItemViewHolder itemViewHolder = (YourItemViewHolder) holder;
//This will remember which one was selected
itemViewHolder.getItemSelectionIndicator()
.setSelected(position == mSelectedPosition);
itemViewHolder.getItemWrapperView()
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(mLogTag, "Tapped on " + position);
//This is the previous selection
notifyItemChanged(mSelectedPosition);
itemViewHolder.getItemSelectionIndicator().setSelected(true);
mSelectedPosition = position;
//This is the new selection
notifyItemChanged(position);
}
});
getItemSelectionIndicator()
and getItemWrapperView()
are methods inside the item's ViewHolder that return specific views from the item layout. A ItemWrapperView could be the top most Linear/RelativeLayout that wraps the entire item. Setting a click listener on it will ensure clicks work if user taps anywhere in the item's view.
ItemSelectionIndicator can be a Linear or RelativeLayout that has been set a state list drawable background. This means when it is set as selected, it shows a shape drawable automatically to indicate selection. When it is set as unselected, the drawable will be removed automatically. This is what the indicator view looks like:
<RelativeLayout
android:id="@+id/selection_indicator"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/selection_indicator_state_list"/>
This is selection_indicator_state_list.xml in res/drawable:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Selected background -->
<item android:state_selected="true"
android:drawable="@drawable/item_selection_shape"/>
<!-- Unselected background -->
<item android:state_selected="false"
android:drawable="@color/transparent"/>
</selector>
And this is item_selection_shape.xml in res/drawable:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
//22 is value of transparency, BDBDBD is the color
<solid android:color="#22BDBDBD"/>
<stroke android:width="2dp" android:color="@color/md_blue_600"/>
<corners
android:radius="3dp"/>
</shape>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With