Search code examples
androidlistviewtextviewandroid-imageviewandroid-recyclerview

RecyclerView ambiguos setVisibility function, clicking on one view affects multiple views


This is the project I am trying to run. Here is my code for the onBindViewHolder from RecyclerView.Adapter class

@Override
    public void onBindViewHolder(ViewHolder holder, final int position) {

        TextView title = (TextView) holder.view.findViewById(R.id.title);
        final TextView desc = (TextView) holder.view.findViewById(R.id.desc);
        final ImageView imageView = (ImageView) holder.view.findViewById(R.id.imageView);

        title.setText(pojos.get(position).getTitle());
        desc.setText(pojos.get(position).getDesc());

        imageView.setImageResource(pojos.get(position).getImage());

        imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                desc.setText("clicked");
                desc.setBackgroundColor(Color.BLUE);
                imageView.setImageResource(R.drawable.heart_red);
            }
        });

    }

The list loads fine, the problem happens when the imageView's onclicklistener is called.

desc.setText("clicked");

The line above makes the change in the list item on which it was clicked on. but

 desc.setBackgroundColor(Color.BLUE);

when this line is executed, the change reflects in multiple items on the list. What is going wrong? In the pictures shown below, I clicked on item 0, the text changes to "clicked" and color is set. But when I scroll down, item 12 has also been affected from my click on item 0. Only the background color change has reflected, not the text change. How do I stop this?

enter image description here

enter image description here

I have been trying to solve this for a long time, kindly download the project and try executing the code to understand what I exactly mean, if my question is not clear.


Solution

  • This happens because the views get recycled and reused.

    So when the view gets recycled, it retains properties of the "old" view if you don't change them again. So when you scroll down to number 12, the view that used to hold number 1 gets recycled (as it can't be seen on the screen anymore), and is used to create number 12. This is why the blue color is on number 12.

    When the item is, for example, clicked, you'll need to save a "clicked" value into your POJO object. Then when the item is drawn, check that value and set the correct image / background color depending on that value.

    I've done this in the below code, so it should give you a rough idea of what to do:

    @Override
    public void onBindViewHolder(ViewHolder holder, final int position) {
        TextView title = (TextView) holder.view.findViewById(R.id.title);
        final TextView desc = (TextView) holder.view.findViewById(R.id.desc);
        final ImageView imageView = (ImageView) holder.view.findViewById(R.id.imageView);
    
        final MyPojo pojo = pojos.get(position);
    
        title.setText(pojo.getTitle());
        if(!pojo.clicked) {
            desc.setText(pojo.getDesc());
            imageView.setImageResource(pojo.getImage());
            desc.setBackgroundColor(Color.argb(0,0,0,0));
        } else {
            desc.setText("clicked");
            desc.setBackgroundColor(Color.BLUE);
            imageView.setImageResource(R.drawable.heart_red);
        }
    
        imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                pojo.clicked = true;
                desc.setText("clicked");
                desc.setBackgroundColor(Color.BLUE);
                imageView.setImageResource(R.drawable.heart_red);
            }
        });
    }
    

    And i've added a "clicked" boolean to the MyPojo class.

    public class MyPojo {
    
        String title;
        String desc;
        int image;
        boolean clicked;
     }