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

This is the project I'm trying to run. Here is my code for 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 occurs when calling imageView onclicklistener.

 desc.setText("clicked"); 

The line above makes a change to the list item that it was clicked on. but

  desc.setBackgroundColor(Color.BLUE); 

when this line is completed, the change reflects several items in the list. What is going wrong? In the figures below, I clicked on element 0, the text changed to “click” and the color was set. But when I scroll down, element 12 was also affected from my click on element 0. Only the background color was changed, not the text change. How to stop it?

enter image description here

enter image description here

I tried to solve this for a long time, kindly download the project and try to execute the code to understand what I definitely mean if my question is not clear.

+8
android listview textview android-imageview android-recyclerview
source share
5 answers

This is because views are returned and reused.

Therefore, when a view returns, it retains the properties of the "old" view, unless you change them again. Therefore, when you scroll down to number 12, the view that is used to store number 1 is processed (since it can no longer be seen on the screen) and used to create number 12. That's why the blue color is on number 12.

When an element, for example, has clicked, you need to save the "clicked" value in your POJO object. Then, when the element is drawn, check this value and set the correct image / background color depending on this value.

I did this in the code below, so it should give you a general 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 added a "clicked" boolean to the MyPojo class.

 public class MyPojo { String title; String desc; int image; boolean clicked; } 
+11
source share

Just add the method to your adapter class after the getItemCount method

 @Override public int getItemViewType(int position) { return position; } 

he will solve the problem

+6
source share

It looks like you have a confusion about using RecyclerView by calling findViewById on onBindViewHolder. These expensive searches should occur in the onCreateViewHolder, where you view all the views and save their links to your custom holder. I went further, looked at your code in the github repository and suggested the following changes:

 public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { private ArrayList<MyPojo> pojos; // Provide a reference to the views for each data item // Complex data items may need more than one view per item, and // you provide access to all the views for a data item in a view holder public static class ViewHolder extends RecyclerView.ViewHolder { // each data item is just a string in this case public TextView title; public TextView desc; public ImageView imageView; public ViewHolder(View v) { super(v); // all expensive findViewById lookups happen in ViewHolder constructor, // which is called only when onCreateViewHolder is called this.title = (TextView) v.findViewById(R.id.title); this.desc = (TextView) v.findViewById(R.id.desc); this.imageView = (ImageView) v.findViewById(R.id.imageView); } } // Provide a suitable constructor (depends on the kind of dataset) public MyAdapter(ArrayList<MyPojo> pojos) { this.pojos = pojos; } // Create new views (invoked by the layout manager) @Override public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { // create a new view View v = LayoutInflater.from(parent.getContext()) .inflate(R.layout.row, parent, false); // set the view size, margins, paddings and layout parameters ViewHolder vh = new ViewHolder(v); return vh; } // Replace the contents of a view (invoked by the layout manager) @Override public void onBindViewHolder(ViewHolder holder, final int position) { // this callback will be constantly called during scrolling // therefore, to make it smooth, we should not make any expensive operations here // - get element from your dataset at this position // - replace the contents of the view with that element holder.title.setText(pojos.get(position).getTitle()); holder.desc.setText(pojos.get(position).getDesc()); holder.imageView.setImageResource(pojos.get(position).getImage()); // you'll need to implement this function based on the way you decide to save clicked state for each clicked view if(isClickedState(position)) { holder.imageView.setImageResource(R.drawable.heart_red); } else { // provide some default background holder.imageView.setImageResource(R.drawable.default); } holder.imageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // you'll need to implement this function to save clicked position saveClickForPosition(position) imageView.setImageResource(R.drawable.heart_red); } }); } // Return the size of your dataset (invoked by the layout manager) @Override public int getItemCount() { return pojos.size(); } } 

This should be the starting point for your debugging, as the following template will ensure proper processing.

As mentioned in another answer, you need to remember the click state for each element, and saving this state in the MyPojo object or elsewhere should be relatively easy to accomplish.

+2
source share

I had a similar problem (there was a change in the number in several elements of the list, not just one). I assume that due to how the view works, I was able to fix it by installing everything that I planned to change, regardless of what I want by default.

IE: if you want to change the background to blue when you load the list, set those that should not be blue to gray (or whatever you want by default).

so that:

 ViewHolder vh = new ViewHolder(v); return vh; 

you want to specify default values

0
source share

try using this adapter:

 public class myAdapter extends RecyclerView.Adapter<CopyOfConversationAdapter.ViewHolder> { private ArrayList<conversationItem> pojos; // inner class to hold a reference to each item of RecyclerView public static class ViewHolder extends RecyclerView.ViewHolder { TextView title; TextView desc; ImageView imageView; public ViewHolder(View itemLayoutView) { super(itemLayoutView); title= (TextView) itemLayoutView.findViewById(R.id.title); desc= (TextView) itemLayoutView.findViewById(R.id.desc); imageView= (ImageView) itemLayoutView.findViewById(R.id.imageView); } } // Return the size of your itemsData (invoked by the layout manager) @Override public int getItemCount() { return pojos.size(); } public CopyOfConversationAdapter(Pojos[] pojos) { this.pojos = new ArrayList<conversationItem>(); this.pojos.addAll(Arrays.asList(Items)); } // Create new views (invoked by the layout manager) @Override public CopyOfConversationAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { // create a new view View itemLayoutView; itemLayoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.comments_item_layout_, null); ViewHolder viewHolder = new ViewHolder(itemLayoutView); return viewHolder; } // Replace the contents of a view (invoked by the layout manager) @Override public void onBindViewHolder(ViewHolder viewHolder, final int position) { // - get data from your itemsData at this position // - replace the contents of the view with that itemsData viewHolder.title.setText(pojos.get(position).getSender()); viewHolder.desc.setText(pojos.get(position).getSnippet()); viewHolder.imageView.setText(pojos.get(position).getIcon()); viewHolder.imageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub desc.setText("clicked"); desc.setBackgroundColor(Color.BLUE); imageView.setImageResource(R.drawable.heart_red); } }); } 

}

-one
source share

All Articles