I've been trying to use the new RecyclerView widget for a couple of days now and thought I've managed to create a Horizontal and Grid layout and also overcome the fact that it lacks of a straightforward way of implementing a OnClickListener (I used GreenRobot's EventBus for this) , I'm still having a hard time selecting an item and preserving that state (style) throughout the recycling process.
This is the code I'm using for my adapter
public class ArticuloItemAdapter extends RecyclerView.Adapter<ArticuloItemAdapter.ItemHolder> {
private ArrayList<ArticuloObject> mItems;
private LayoutInflater mLayoutInflater;
private int mSize;
private int mSelectedPosition;
private RecyclerView mRecyclerView;
public ArticuloItemAdapter(Context context, RecyclerView rv, ArrayList<ArticuloObject> articulos) {
mLayoutInflater = LayoutInflater.from(context);
mItems=articulos ;
mSize = context.getResources()
.getDimensionPixelSize(R.dimen.icon);
mSelectedPosition = -1;
mRecyclerView = rv;
}
@Override
public ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = mLayoutInflater.inflate(R.layout.gallery_recycler_row, parent, false);
return new ItemHolder(itemView, this);
}
@Override
public void onBindViewHolder(ItemHolder holder, int position) {
Ion.with(holder.getPicImageView())
.placeholder(R.drawable.owner_placeholder)
.resize(mSize, mSize)
.centerCrop()
.error(R.drawable.owner_error)
.load(mItems.get(position).getUrl());
//Update the views as they got recycled
if (mSelectedPosition != position) {
holder.getPicImageView().setBackgroundColor(Color.TRANSPARENT);
} else {
holder.getPicImageView().setBackgroundColor(Color.CYAN);
}
}
@Override
public int getItemCount() {
return mItems.size();
}
public int getSelectedPosition() {
return mSelectedPosition;
}
public void setSelectedPosition(int mSelectedPosition) {
this.mSelectedPosition = mSelectedPosition;
}
public RecyclerView getRecyclerView() {
return mRecyclerView;
}
/* Required implementation of ViewHolder to wrap item view */
public class ItemHolder extends RecyclerView.ViewHolder implements
View.OnClickListener {
private ArticuloItemAdapter mParent;
private ImageView mPicImageView;
public ItemHolder(View itemView, ArticuloItemAdapter parent) {
super(itemView);
itemView.setOnClickListener(this);
mParent = parent;
mPicImageView = (ImageView) itemView.findViewById(R.id.picture_image_view);
}
public ImageView getPicImageView() {
return mPicImageView;
}
@Override
public void onClick(View v) {
EventBus.getDefault().post(new OnArticuloCartaClickEvent(this, getPosition()));
setItemActivated(v);
}
public void setItemActivated(View v) {
//Check position of previous selected item. The first time an item is selected, the previous position will be -1
if (mParent.getSelectedPosition() >= 0) {
ItemHolder row = (ItemHolder) mParent.getRecyclerView().findViewHolderForPosition(mParent.getSelectedPosition());
if (row != null) {
row.getPicImageView().setBackgroundColor(Color.TRANSPARENT);
}
}
mParent.setSelectedPosition(getPosition());
v.findViewById(R.id.picture_image_view).setBackgroundColor(Color.CYAN);
}
}
}
Now in the code shown above, all I'm doing to keep track of the selected item is the following:
I. In the onClick(View v) event:
- Whenever an item is clicked, I call the
setItemActivated
method - In the setItemActivated method, I check if the selectedPosition is greater than or equal to 0 ( the default is -1 when no item is selected).
- If the previous condition is true I try to get the
ViewHolder
in that position and if that View is not null, I change the background colour of theImageView
back to it's original background colour (transparent) - Set the new value of mSelectedPosition to the current position using
getPosition()
- Finally, change the background colour of the
ImageView
inside the currentViewHolder
to a different colour (CYAN in this case)
II. In the onBindViewHolder(ItemHolder holder, int position) method:
If position of selected item (mSelectedPosition) is different from
the position of the view being displayed, I change the background
colour of the ImageView
back to its default colour.
Otherwise, I change the colour of the ImageView
to the colour used to identify a selected item (CYAN).
All this works as long as the RecyclerView has a considerable number of item that it needs to start recycling the views. But if it doesn't, like in my case, I've noticed that findViewHolderForPosition
always returns null, and as a result, I cannot change the colour of the previously selected item back to its default colour and so I ended up with more than one item selected.
And to make matters worse, as the RecyclerView
doesn't have to recycle anything, the onBindViewHolder
method never gets call and therefore I can't count on the code inside to adjust the colour of the items accordingly.
Please, I'd really appreciate if anyone could tell me what I'm doing wrong here or perhaps give some ideas. It's really frustrating not being able to do something as basic as selecting an item.
Thanks in advance.