Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to keep track of the selected items in a RecyclerView in Android?

How does one achieve a consistent item selection with RecyclerView ? I get the whole idea of RecyclerView recycling old views and what not. My problem is I have a list of items with an icon on each item, when an item is clicked, the icon changes colour. I managed to achieve all of this, but I just realised, as I scroll down the list, that other items have their icons changed too, and when I scroll back to the item I clicked on, the icon is no longer in the "clicked color".

Does anyone know how to keep track of the selected items? I keep seeing something called SparseBooleanArray, but I am not sure how to implement it.

Here is my adapter code:

public class TableRVAdapter extends RecyclerView.Adapter<TableRVAdapter.TableHolder> {

    List<Tables> tableList;
    private SparseBooleanArray selectedItems;

    public TableRVAdapter(List<Tables> tableList)
    {
        this.tableList = tableList;
        selectedItems = new SparseBooleanArray();
       // setHasStableIds(true);
    }
    class TableHolder extends RecyclerView.ViewHolder
    {
        TextView tableTV;
        CardView tableCV;
        View circle;
        View parentView;
        TableHolder(final View itemView)
        {
            super(itemView);
            tableTV = (TextView)itemView.findViewById(R.id.tableTV);
            tableCV = (CardView)itemView.findViewById(R.id.tableCV);
            circle = itemView.findViewById(R.id.statusCircle);
            itemView.setClickable(true);
            parentView = itemView;

            tableCV.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                     circle.setBackgroundResource(R.drawable.circle);

                }
            });
        }
        /*
        @Override
        public void onClick(View view) {
            if (selectedItems.get(getAdapterPosition(), false)) {
                tableCV.setSelected(false);
                circle.setBackgroundResource(R.drawable.circle2);
            }
            else {
                selectedItems.put(getAdapterPosition(), true);
                tableCV.setSelected(true);
                circle.setBackgroundResource(R.drawable.circle);
            }

        }*/
    }

    @Override
    public TableHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.table_item,parent,false);
        TableHolder tableHolder = new TableHolder(view);
        return tableHolder;
    }

    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView)
    {
        super.onAttachedToRecyclerView(recyclerView);
    }


    @Override
    public void onBindViewHolder(TableHolder holder, int position) {
        holder.tableTV.setText(tableList.get(position).getTableNumber());

    }

    /**
     * Returns the total number of items in the data set hold by the adapter.
     *
     * @return The total number of items in this adapter.
     */
    @Override
    public int getItemCount() {
        return tableList.size();
    }

}
like image 536
spongyboss Avatar asked Jul 15 '15 10:07

spongyboss


2 Answers

I know this question is already answered but someone might find this answer useful and easier.

There is one useful method in the recycler view is onViewRecycled.

This can help you to get away from the pressed state. When working with the images/drawables in the recylcer view when some of the elements doesn't use the drawables, previews recycler view's drawn image will be present and it makes look all the data wrong as it happened with you with your selected view.

To achieve this in a more simpler way you can use this method to clear the drawn images to reset its values.

For example, you mark you selected element's background to green, and some of your views contains images(Note: Only some of your elements), than use this method as like this:

@Override
        public void onViewRecycled(MyViewHolder holder) {
            super.onViewRecycled(holder);

            // Set ImageView's Drawable as transperent
            holder.myImageView.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), android.R.color.transparent));

            // Set background color as transperent
            holder.bgContainer.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), android.R.color.transparent));

        }

And now you can manage an ArrayList of integers with ids/position of selected elements (using onClick method on recycler view's item).

With onBindViewHolder(MyViewHolder myViewHolder, int position) you can normally fill the data. And for setting background you can simply check if the id/position is in ArrayList or not (If true, set background color green else leave it as it is. As it will be managed by onViewRecylcer method and wont affect other scrolled items with green background even if it is not selected).

Hope it will help someone and make the recyler view with selection a bit more easier.

like image 142
kirtan403 Avatar answered Sep 18 '22 10:09

kirtan403


RecyclerView.adapter has got 2 important functions to override:

onCreateViewHolder(parent, viewType)
onBindVIewHolder(viewholder, position)

The first function is used to inflate views that will be used inside the recyclerview, the second is used to bind the data you have to this view, and thus set the correct viewstate on the view.

The recyclerview itself will only inflate a certain amount of views and then will start to re-use already inflated views (hence recyclerview). So you need to set the correct state for each item in onBindViewholder() and use the item in your collection on that position to set the correct viewState. For your example: change the color of the icon, dependent on a boolean value in your objects, eg : isPressed

like image 39
ThMBc Avatar answered Sep 20 '22 10:09

ThMBc