Nipuna Dilhara Nipuna Dilhara - 3 months ago 15
Android Question

How to change the color of vector assigned to ImageButton in a RecyclerView?

I have a recyclerview which shows several(8) cardviews. Inside each cardview, there are several elements like text, imagebutton,etc. Inside the Adapter class (RvAdapter extends RecyclerView.Adapter) I have a code as below. What I want to do is change the color of Vector (.xml) assigned to the imagebutton using the OnClickListener of the same button.

public RvAdapter(Context context,List<Person> persons) {
this.mContext=context;
this.persons=persons;
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
View v= LayoutInflater.from(parent.getContext()).inflate(R.layout.card_view_content,parent,false);
ViewHolder vh=new ViewHolder(v);
return vh;
}

@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
final ViewHolder mHolder=holder;
mHolder.personName.setText(persons.get(position).name);
mHolder.personAge.setText(( persons.get(position).age));

mHolder.cvCard.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(mContext,"card number:"+String.valueOf(position),Toast.LENGTH_SHORT).show();
}
});

//this is where the error comes
mHolder.alarmImageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//this code line doesnt work
//mHolder.alarmImageButton.setColorFilter(R.color.colorAccent);

//this code line works... but it changes the imagebutton color of another card view at below of the recycler view
mHolder.alarmImageButton.setColorFilter(Color.argb(255,255,255,255));
Toast.makeText(mContext,"button:"+String.valueOf(position),Toast.LENGTH_SHORT).show();
}
});
}


RecyclerView has 8 cardviews inside it. When the imagebutton of the first cardview's imagebutton is clicked, it changes the color to white. But the error is it changes the color of 7th card's imagebutton color too. When the second cardview's imagebutton is clicked it changes the 8th card's imagebutton color too. However, the Toast works fine. It shows that click event has identify the position of each cardview and imagebutton properly.

I just couldn't figure this out properly. How the 1st card 7th card views are connected with each other ?

This is my ViewHolder class

public class ViewHolder extends RecyclerView.ViewHolder{
CardView cvCard;
TextView personName;
TextView personAge;
ImageButton alarmImageButton;
public ViewHolder(View itemView) {
super(itemView);
cvCard=(CardView)itemView.findViewById(R.id.cv_card);
personName=(TextView)itemView.findViewById(R.id.txt_person_name);
personAge=(TextView)itemView.findViewById(R.id.txt_person_age);
alarmImageButton=(ImageButton)itemView.findViewById(R.id.alarm_image_button);
}


It will be a great help if someone can help me to find this error...

Answer Source

I just couldn't figure this out properly. How the 1st card 7th card views are connected with each other?

The point of using a RecyclerView is that the Views are getting recycled. You set the colorFilter of the ImageButton, but that same button may be used in a recycled View also.

You should store the clicked state of your RecyclerView rows and set the colorFilter accordingly on each ImageButton in onBindViewHolder().

For example:

// a HashSet to store the clicked positions
private HashSet<Integer> clickedPositions = new HashSet<>();

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    final ViewHolder mHolder = holder;
    mHolder.personName.setText(persons.get(position).name);
    mHolder.personAge.setText((persons.get(position).age));

    mHolder.cvCard.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Toast.makeText(mContext, "card number:" + String.valueOf(position),
                    Toast.LENGTH_SHORT).show();
        }
    });

    if (clickedPositions.contains(mHolder.getAdapterPosition())) {
        // the current item is clicked, change its color
        mHolder.alarmImageButton.setColorFilter(Color.argb(255, 255, 255, 255));
    } else {
        // else change it to another color
        mHolder.alarmImageButton.setColorFilter(Color.argb(0, 0, 0, 0));
    }

    mHolder.alarmImageButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Toast.makeText(mContext, "button:" + String.valueOf(position),
                    Toast.LENGTH_SHORT).show();

            // if the item is already clicked, remove it from the clicked items
            if (!clickedPositions.remove(mHolder.getAdapterPosition())) {
                // if not clicked, add it to the clicked items
                clickedPositions.add(mHolder.getAdapterPosition());
            }
            // and notify the Adapter that the item is changed
            notifyItemChanged(mHolder.getAdapterPosition());
        }
    });
}