RecyclerView ambiguos setVisibility функция, нажатие на один вид влияет на несколько просмотров

Это проект, который я пытаюсь запустить. Вот мой код для onBindViewHolder из класса RecyclerView.Adapter

@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); } }); } 

Список загружается отлично, проблема возникает, когда вызывается onclicklistener imageView.

 desc.setText("clicked"); 

В приведенной выше строке делается изменение в элементе списка, на который он был нажат. но

  desc.setBackgroundColor(Color.BLUE); 

Когда эта строка выполняется, изменение отражает несколько элементов в списке. Что происходит не так? На приведенных ниже рисунках я нажал на элемент 0, текст изменился на «щелкнуть» и установлен цвет. Но когда я прокручиваю вниз, элемент 12 также был затронут из моего клика по элементу 0. Только изменение цвета фона отразилось, а не изменение текста. Как это остановить?

Введите описание изображения здесь

Введите описание изображения здесь

Я пытался решить это в течение долгого времени, любезно загрузите проект и попробуйте выполнить код, чтобы понять, что я точно имею в виду, если мой вопрос не ясен.

Solutions Collecting From Web of "RecyclerView ambiguos setVisibility функция, нажатие на один вид влияет на несколько просмотров"

Это происходит потому, что представления возвращаются и используются повторно.

Поэтому, когда представление перерабатывается, оно сохраняет свойства «старого» представления, если вы не измените их снова. Поэтому, когда вы прокручиваете вниз до номера 12, представление, используемое для хранения номера 1, перерабатывается (поскольку его больше нельзя увидеть на экране) и используется для создания номера 12. Вот почему синий цвет находится на номере 12.

Когда элемент, например, щелкнул, вам нужно сохранить «щелкнув» значение в свой объект POJO. Затем, когда элемент рисуется, проверьте это значение и установите правильный цвет изображения / фона в зависимости от этого значения.

Я сделал это в приведенном ниже коде, поэтому он должен дать вам общее представление о том, что делать:

 @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); } }); } 

И я добавил «clicked» логическое в класс MyPojo.

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

Просто добавьте метод в свой класс адаптера после метода getItemCount

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

Это решит проблему

Похоже, что у вас есть путаница в использовании RecyclerView, вызывая findViewById в onBindViewHolder. Эти дорогостоящие поисковые запросы должны происходить в onCreateViewHolder, где вы просматриваете все виды и сохраняете их ссылки на свой пользовательский держатель. Я пошел дальше, посмотрел ваш код в репозитории github и предложил следующие изменения:

 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's 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(); } } 

Это должно быть отправной точкой для вашей отладки, так как следующая эта схема гарантирует правильную рециркуляцию.

Как уже упоминалось в другом ответе, вам нужно запомнить состояние щелчка для каждого элемента, и сохранение этого состояния в объекте MyPojo или в другом месте должно быть относительно легко выполнить.

У меня была аналогичная проблема (было изменение числа в нескольких элементах списка, а не только на одном). Я предполагаю, что из-за того, как работает просмотр, я смог исправить это, установив все, что я планировал изменить, независимо от того, что я хочу по умолчанию.

IE: если вы хотите изменить фон на синий, когда вы загружаете список, установите те, которые не должны быть синим до серого (или тем, что вы хотите по умолчанию).

так вот:

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

Вы хотите указать значения по умолчанию

Здесь попробуйте использовать этот адаптер:

 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); } }); } 

}