【问题标题】:CheckBox in RecyclerView keeps on checking different itemsRecyclerView 中的 CheckBox 不断检查不同的项目
【发布时间】:2015-12-02 08:57:22
【问题描述】:

这是我在 RecyclerView 中的项目的 XML

<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/cvItems"
    android:layout_height="wrap_content"
    android:layout_width="fill_parent"
    android:layout_margin="2dp"
    card_view:cardElevation="0dp"
    card_view:contentPadding="0dp"
    card_view:cardBackgroundColor="#FFFFFF"
    >

    <LinearLayout
        android:orientation="horizontal"
        android:layout_height="fill_parent"
        android:layout_width="fill_parent">
        <TextView
            android:layout_width="0dip"
            android:layout_height="match_parent"
            android:layout_weight="0.8"
            android:id="@+id/tvContent"
            android:textSize="15dp"
            android:paddingLeft="5dp"
            android:paddingRight="5dp" />
        <CheckBox
            android:id="@+id/cbSelect"
            android:layout_width="0dip"
            android:layout_weight="0.2"
            android:layout_height="match_parent"
            android:button="@drawable/cb_checked"
            android:gravity="center_horizontal"
            android:textAlignment="center"
            android:layout_gravity="center_horizontal" />
    </LinearLayout>
</android.support.v7.widget.CardView>

这里是 RecyclerView 适配器,它为上面的每个项目扩展布局:

public class AdapterTrashIncome extends RecyclerView.Adapter<AdapterTrashIncome.ViewHolder> {

    private ArrayList<ObjectIncome> myItems = new ArrayList<>();

    public AdapterTrashIncome(ArrayList<ObjectIncome> getItems, Context context){
        try {
            mContext = context;
            myItems = getItems;
        }catch (Exception e){
            Log.e(FILE_NAME, "51: " + e.toString());
            e.printStackTrace();
        }
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        public TextView tvContent;
        public CheckBox cbSelect;

        public ViewHolder(View v) {
            super(v);
            tvContent = (TextView) v.findViewById(R.id.tvContent);
            cbSelect = (CheckBox) v.findViewById(R.id.cbSelect);
        }
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, final int position) {
        final ObjectIncome objIncome = myItems.get(position);
        String content = "<b>lalalla</b>";
        holder.tvContent.setText(Html.fromHtml(content));
    }
}

问题是,假设我在 RecyclerView 中有 10 个项目。当我选中项目 1,2,3 上的复选框时,我向下滚动 RecyclerView,突然检查了其他一些项目,例如项目 8,9。当我再次向上滚动时,第 1 项和第 3 项被选中,但第 2 项未选中。知道为什么会这样吗?

【问题讨论】:

  • 尝试使用this library,参见ViewStates。它有助于在滚动时保存状态。

标签: android android-recyclerview


【解决方案1】:

这是预期的行为。你没有设置你的复选框被选中。您正在选择一个,并且 View holder 将其保持选中状态。您可以将布尔变量添加到您的 ObjectIncome 对象中并保持您的项目的选择状态。

你可以看看我的例子。你可以这样做:

public class AdapterTrashIncome extends RecyclerView.Adapter<AdapterTrashIncome.ViewHolder> {

    private ArrayList<ObjectIncome> myItems = new ArrayList<>();

    public AdapterTrashIncome(ArrayList<ObjectIncome> getItems, Context context){
        try {
            mContext = context;
            myItems = getItems;
            }catch (Exception e){
            Log.e(FILE_NAME, "51: " + e.toString());
            e.printStackTrace();
        }
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        public TextView tvContent;
        public CheckBox cbSelect;

        public ViewHolder(View v) {
            super(v);
            tvContent = (TextView) v.findViewById(R.id.tvContent);
            cbSelect = (CheckBox) v.findViewById(R.id.cbSelect);
        }
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, final int position) {
        final ObjectIncome objIncome = myItems.get(position);
        String content = "<b>lalalla</b>";
        holder.tvContent.setText(Html.fromHtml(content));

        //in some cases, it will prevent unwanted situations
        holder.cbSelect.setOnCheckedChangeListener(null);

        //if true, your checkbox will be selected, else unselected
        holder.cbSelect.setChecked(objIncome.isSelected());

        holder.cbSelect.setOnCheckedChangeListener(new OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    //set your object's last status
                    objIncome.setSelected(isChecked);
            }
        });

    }
}

【讨论】:

  • 它没有用。你必须在holder.cbSelect.setChecked(objIncome.isSelected()) 之前写holder.cbSelect.setOnCheckedChangeListener(null);
  • 设置 holder.cbSelect.setOnCheckedChangeListener(null); 有什么原因吗?有效吗?
  • @oguzhand 嗨,我尝试了您的解决方案,但无论哪种方式都不起作用:无论是否将侦听器设置为 null。
  • @oguzhand 这是来自onBindViewHolder 的代码。 @Override public void onBindViewHolder(final ItemHolder holder, int position) { holder.checkBox.setOnCheckedChangeListener(null); holder.checkBox.setSelected(list.get(position).isSelected()); holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { list.get(holder.getAdapterPosition()).setSelected(isChecked); } });
  • 您不必调用 setOnCheckedChangeListener(null)。只需检查按钮是否被按下。像这样: cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(final CompoundButton CompoundButton, boolean checked) { if (compoundButton.isPressed()) { //在这里做你的工作}}
【解决方案2】:

简而言之,是因为回收视图并再次使用它们!

如何避免这种情况:

1.在onBindViewHolder 中检查是否应该选中或取消选中复选框。 不要忘记把 if 和 else 放在一起

if (...)
    holder.cbSelect.setChecked(true);
else
    holder.cbSelect.setChecked(false);
  1. 为复选框设置监听器!每当其检查状态发生变化时,也要更新您的 myItems 数组中的相应对象!因此,每当显示新视图时,它都会读取对象的最新雕像。

【讨论】:

  • 你的第二点是关键。虽然它在某种情况下效果最好,但当初始数据集还包含有关检查状态的信息时(对我来说就是这种情况)
  • 这是更直接和正确的答案。 SetCheck for BOTH true and false in onBindViewHolder 是关键
  • 在我的情况下,我必须将数据模型中的数据保存为默认值isCheckedfalse,以便在开始时设置所有数据,然后onCheckChanged我刚刚更新了isCheckedtruefalse 并在答案中告知检查是否已检查。
【解决方案3】:

只需添加RecyclerView的两个覆盖方法

@Override
public long getItemId(int position) {
    return position;
}

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

【讨论】:

  • 不要那样做!!它将绕过recyclerView回收机制,失去使用它的全部意义。
  • 不,它不会,它只是返回视图持有者中每个回收视图的确切位置。
  • Harish,也许我遗漏了一些东西,但据我所知,通过这样做,您实际上告诉适配器项目类型的数量就是项目数量。意思是没有一个项目可以回收,因为它没有相似的视图。虽然很容易测试。只需在 onBindViewHolder 中记录 viewHolder.itemView 引用,看看是否有两个 viewHolder 持有相同的视图引用。测试应该在一个很长的列表中,以便执行回收系统。
  • 它完美地唤醒了,它拯救了我的一天。
  • 如果您的 recyclerview 中有超过 100 个项目,此解决方案将一次加载所有项目,如果您有图像,这可能会导致 OutOfMemoryException,否则此解决方案是完美的@Kundan
【解决方案4】:

仅当您的回收站视图中的项目数量有限时才使用此选项。
我尝试在模型中使用布尔值并保持复选框状态,但在我的情况下它没有帮助。 对我有用的是 this.setIsRecyclable(false);

public class ComponentViewHolder extends RecyclerView.ViewHolder {
    public MyViewHolder(View itemView) {
        super(itemView);
        ....
        this.setIsRecyclable(false);
    }

更多解释可以在这里找到https://developer.android.com/reference/android/support/v7/widget/RecyclerView.ViewHolder.html#isRecyclable()

注意:这是一种解决方法。要正确使用它,您可以参考文档,其中指出 “对 setIsRecyclable() 的调用应始终配对(对 setIsRecyclabe(false) 的调用应始终与稍后对 setIsRecyclable(true) 的调用相匹配)。成对调用可能是嵌套的,因为状态是内部引用计数的。”如果有人可以提供更多代码,我不知道如何在代码中执行此操作。

【讨论】:

  • 请您解释一下如何使用它?
  • 这不是浪费recyclerView背后的逻辑吗?
  • 我用长列表尝试了这个,它解决了随机检查问题,但是当我向下滚动并用长列表重新向上滚动时,选中的复选框消失了:(
  • 让视图不可回收不是一个好主意,因为它会耗尽内存,您将失去回收视图的大部分好处。
  • 我同意你们,@eren130 和 Arthur。我已经编辑了这篇文章,如果我们能想出一种使用 setIsRecyclable(true / false); 的方法,我将不胜感激。正确。
【解决方案5】:

您可以使用 Model 类来跟踪每个 recyclerView 项目的复选框。 完整参考来自:RecyclerView Checkbox Android

setTaggetTag 用于跟踪复选框状态。查看完整参考链接以获取更多信息。它还教授如何将选中的项目发送到 NEXTACTIVITY

制作模型

public class Model {

    private boolean isSelected;
    private String animal;

    public String getAnimal() {
        return animal;
    }

    public void setAnimal(String animal) {
        this.animal = animal;
    }

    public boolean getSelected() {
        return isSelected;
    }

    public void setSelected(boolean selected) {
        isSelected = selected;
    }
}

创建整数.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <integer name="btnplusview">1</integer>
    <integer name="btnpluspos">2</integer>
</resources>

最后适配器看起来像这样:

 import android.content.Context;
 import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
    import android.view.View;
 import android.view.ViewGroup;
 import android.widget.CheckBox;
 import android.widget.TextView;
 import android.widget.Toast;

 import java.util.ArrayList;


  public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.MyViewHolder> {

private LayoutInflater inflater;
public static ArrayList<Model> imageModelArrayList;
private Context ctx;

public CustomAdapter(Context ctx, ArrayList<Model> imageModelArrayList) {

    inflater = LayoutInflater.from(ctx);
    this.imageModelArrayList = imageModelArrayList;
    this.ctx = ctx;
}

@Override
public CustomAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    View view = inflater.inflate(R.layout.rv_item, parent, false);
    MyViewHolder holder = new MyViewHolder(view);

    return holder;
}

@Override
public void onBindViewHolder(final CustomAdapter.MyViewHolder holder, int position) {

    holder.checkBox.setText("Checkbox " + position);
    holder.checkBox.setChecked(imageModelArrayList.get(position).getSelected());
    holder.tvAnimal.setText(imageModelArrayList.get(position).getAnimal());

   // holder.checkBox.setTag(R.integer.btnplusview, convertView);
    holder.checkBox.setTag(position);
    holder.checkBox.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            Integer pos = (Integer) holder.checkBox.getTag();
            Toast.makeText(ctx, imageModelArrayList.get(pos).getAnimal() + " clicked!", Toast.LENGTH_SHORT).show();

            if (imageModelArrayList.get(pos).getSelected()) {
                imageModelArrayList.get(pos).setSelected(false);
            } else {
                imageModelArrayList.get(pos).setSelected(true);
            }
        }
    });


}

@Override
public int getItemCount() {
    return imageModelArrayList.size();
}

class MyViewHolder extends RecyclerView.ViewHolder {

    protected CheckBox checkBox;
    private TextView tvAnimal;

    public MyViewHolder(View itemView) {
        super(itemView);

        checkBox = (CheckBox) itemView.findViewById(R.id.cb);
        tvAnimal = (TextView) itemView.findViewById(R.id.animal);
    }

}

}

【讨论】:

    【解决方案6】:

    使用 Kotlin 为我解决此问题的唯一方法是在设置变量之前清除 OnCheckedChangeListener,然后在设置 checked 之后创建一个新的 OnCheckedChangeListener

    我在RecyclerView.ViewHolder 中执行以下操作

    task.setOnCheckedChangeListener(null)
    task.isChecked = item.status
    task.setOnCheckedChangeListener { _: CompoundButton, checked: Boolean ->
        item.status = checked
        ...
        do more stuff
        ...
    }
    

    【讨论】:

    • 这是完美的工作。我不知道为什么,但这仅适用于使用 KOTLIN 的人!
    • 这确实有效。他的所作所为非常聪明,同时也很明显。 task.setOnCheckedChangeListener(null) 只是将复选框视为一个全新的复选框,因为我们只对新事件感兴趣。再次非常聪明。
    【解决方案7】:

    我建议不要在recyclerViewAdapter 中使用checkBox.setOnCheckedChangeListener。因为在滚动 recyclerView 时,checkBox.setOnCheckedChangeListener 将被适配器触发。 不安全。相反,请使用 checkBox.setOnClickListener 与用户输入进行交互。

    例如:

         public void onBindViewHolder(final ViewHolder holder, int position) {
            /*
             .
             .
             .
             .
             .
             .
            */
    
            holder.checkBoxAdapterTasks.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    boolean isChecked =  holder.checkBoxAdapterTasks.isChecked();
                    if(isChecked){
                        //checkBox clicked and checked
                    }else{
                        //checkBox clicked and unchecked
                    }
    
                }
            });
    
        }
    

    【讨论】:

      【解决方案8】:

      在我的情况下,这有效。

      @Override
      public void onViewRecycled(MyViewHolder holder) {
          holder.checkbox.setChecked(false); // - this line do the trick
          super.onViewRecycled(holder);
      }
      

      【讨论】:

      • 由于某种原因,这个解决方案非常完美!
      【解决方案9】:

      如上所述,对象的选中状态应包含在对象属性中。在某些情况下,您可能还需要通过单击对象本身来更改对象选择状态,并让 CheckBox 通知实际状态(选中或未选中)。然后,复选框将使用给定适配器实际位置的对象状态,即(默认情况下/在大多数情况下)列表中元素的位置。

      检查下面的sn-p,它可能有用。

      import android.content.Context;
      import android.graphics.Bitmap;
      import android.net.Uri;
      import android.provider.MediaStore;
      import android.support.v7.widget.RecyclerView;
      import android.view.LayoutInflater;
      import android.view.View;
      import android.view.ViewGroup;
      import android.widget.CheckBox;
      import android.widget.CompoundButton;
      import android.widget.ImageView;
      
      import java.io.File;
      import java.io.IOException;
      import java.util.List;
      
      public class TakePicImageAdapter extends RecyclerView.Adapter<TakePicImageAdapter.ViewHolder>{
          private Context context;
          private List<Image> imageList;
      
          public TakePicImageAdapter(Context context, List<Image> imageList) {
              this.context = context;
              this.imageList = imageList;
          }
      
          @Override
          public TakePicImageAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
              View view= LayoutInflater.from(context).inflate(R.layout.image_item,parent,false);
              return new ViewHolder(view);
          }
      
          @Override
          public void onBindViewHolder(final TakePicImageAdapter.ViewHolder holder, final int position) {
              File file=new File(imageList.get(position).getPath());
              try {
                  Bitmap bitmap= MediaStore.Images.Media.getBitmap(context.getContentResolver(), Uri.fromFile(file));
                  holder.image.setImageBitmap(bitmap
                  );
              } catch (IOException e) {
                  e.printStackTrace();
              }
              holder.selectImage.setOnCheckedChangeListener(null);
              holder.selectImage.setChecked(imageList.get(position).isSelected());
              holder.selectImage.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                  @Override
                  public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                      holder.selectImage.setChecked(isChecked);
                      imageList.get(position).setSelected(isChecked);
                  }
              });
              holder.image.setOnClickListener(new View.OnClickListener() {
                  @Override
                  public void onClick(View v) {
                      if (imageList.get(position).isSelected())
                      {
                          imageList.get(position).setSelected(false);
                          holder.selectImage.setChecked(false);
                      }else
                      {
                          imageList.get(position).setSelected(true);
                          holder.selectImage.setChecked(true);
                      }
                  }
              });
      
          }
      
          @Override
          public int getItemCount() {
              return imageList.size();
          }
      
          public class ViewHolder extends RecyclerView.ViewHolder {
              public ImageView image;public CheckBox selectImage;
              public ViewHolder(View itemView) {
                  super(itemView);
                  image=(ImageView)itemView.findViewById(R.id.image);
                  selectImage=(CheckBox) itemView.findViewById(R.id.ch);
      
              }
          }
      }

      【讨论】:

        【解决方案10】:

        使用数组来保存项目的状态

        在适配器中使用 Map 或 SparseBooleanArray(类似于 map,但它是一个 int 和 boolean 的键值对)来存储我们项目列表中所有项目的状态,然后使用切换选中状态时要比较的键和值

        在适配器中创建一个SparseBooleanArray

        // sparse boolean array for checking the state of the items
        
            private SparseBooleanArray itemStateArray= new SparseBooleanArray();
        

        然后在项目点击处理程序onClick() 使用 itemStateArray 中项目的状态在切换之前检查,这里是一个例子

                @Override
                public void onClick(View v) {
                    int adapterPosition = getAdapterPosition();
                    if (!itemStateArray.get(adapterPosition, false)) {
                        mCheckedTextView.setChecked(true);
                        itemStateArray.put(adapterPosition, true);
                    }
                    else  {
                        mCheckedTextView.setChecked(false);
                        itemStateArray.put(adapterPosition, false);
                    }
                }
        

        另外,使用稀疏布尔数组设置视图绑定时的检查状态

        @Override
        public void onBindViewHolder(ViewHolder holder, int position) {
            holder.bind(position);
        }
        
        @Override
        public int getItemCount() {
            if (items == null) {
                return 0;
            }
            return items.size();
        }
        
         void loadItems(List<Model> tournaments) {
            this.items = tournaments;
            notifyDataSetChanged();
        }
        
        
        class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        
            CheckedTextView mCheckedTextView;
        
            ViewHolder(View itemView) {
                super(itemView);
                mCheckedTextView = (CheckedTextView) itemView.findViewById(R.id.checked_text_view);
                itemView.setOnClickListener(this);
            }
        
            void bind(int position) {
                // use the sparse boolean array to check
                if (!itemStateArray.get(position, false)) {
                    mCheckedTextView.setChecked(false);}
                else {
                    mCheckedTextView.setChecked(true);
                }
            }
        

        最终的适配器就像this

        【讨论】:

          【解决方案11】:

          我在带有开关的 RecyclerView 列表中遇到了同样的问题,并使用@oguzhand 答案解决了它,但在 checkChangeListener 中使用了这段代码:

          if (buttonView.isPressed()) {
              if (isChecked) {
                  group.setSelected(true);
              } else {
                  group.setSelected(false);
              }
          }else{
              if (isChecked) {
                  buttonView.setChecked(false);
              } else {
                  buttonView.setChecked(true);
              }
          }
          

          (其中“组”是我要选择/取消选择的实体)

          【讨论】:

            【解决方案12】:

            您需要将 onBindViewHolder(logic) 与 CheckBox 的交互和用户与复选框的交互分开。我使用 OnCheckedChangeListener 进行用户交互(显然)和 ViewHolder.bind() 用于逻辑,这就是为什么您需要在设置持有者之前和持有者准备好之后将已检查的侦听器设置为 null - 为用户交互配置已检查的侦听器。

            boolean[] checkedStatus = new boolean[numberOfRows];
            
            @Override
                    public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
                    final ViewHolderItem itemHolder = (ViewHolderItem) holder;
            
                    //holder.bind should not trigger onCheckedChanged, it should just update UI
                    itemHolder.checkBox.setOnCheckedChangeListener(null);
            
                    itemHolder.bind(position);
            
                    itemHolder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                        @Override
                        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                            if (isChecked) {
                                checkedStatus[holder.getAdapterPosition()] = true;
                                performCheckedActions(); //your logic here
                            } else {
                                checkedStatus[holder.getAdapterPosition()] = false;
                                performUncheckedActions(); //your logic here
                            }
                        }
                    });
                }
            
            public void bind(int position) {
                        boolean checked = checkedStatus[position];
                        if (checked) {
                            checkBox.setChecked(false);
                        } else {
                            checkBox.setChecked(true);
                        }
                    }
            

            【讨论】:

              【解决方案13】:

              我发现这个解决方案的问题是,通过创建一个静态全局 数组并在“onBindViewHolder”中使用它 ADAPER CLASS ,我在其中创建了所有需要的全局变量/对象。

              public class RVAdapter extends RecyclerView.Adapter<RVAdapter.PersonViewHolder> {
              private Context context;
              public static class PersonViewHolder extends RecyclerView.ViewHolder {
              
                  CardView cv;
                  TextView question,category;
                  TextView personAge;
                  ImageView upvote;
                  Button b1;
                  public static int k;
                  private int visibleThreshold = 5;
                  public static int i=0;
                   static int  check[]; //Static array
                  PersonViewHolder(View itemView,int i) {
                      super(itemView);
                      if(i==PersonViewHolder.k)
                      {
                          b1=(Button)itemView.findViewById(R.id.loadmore);
              
                      }
                      else
                      {
                          cv = (CardView)itemView.findViewById(R.id.cv);
                          question = (TextView)itemView.findViewById(R.id.question);
                          category = (TextView)itemView.findViewById(R.id.text_categ);
                          personAge = (TextView)itemView.findViewById(R.id.text1);
                          upvote = (ImageView)itemView.findViewById(R.id.upvote);
              
                      }
              
                  }
              
              }
              

              在这里(在 RVADAPTER 类的构造器中)我给数组的大小等于我要在回收站视图中显示的项目的大小/no

              List<Person> persons;
              
              RVAdapter(List<Person> persons){
                  this.persons = persons;
                  PersonViewHolder.check=new int[persons.size()];
                  PersonViewHolder.k=persons.size();
              }
              

              BindViewHolder,我,将这个概念应用在一个按钮上,当我点击一个按钮时,按钮的背景图像会发生变化。 我使用的按钮对象名称为“upvote”,因为“i”保存每个项目在回收器视图中的位置,我将其用作数组的索引,该数组用作标志并跟踪元素的状态。

              @Override
              public void onBindViewHolder(final PersonViewHolder personViewHolder, final int i) {
                  if(i==PersonViewHolder.k) {
                      personViewHolder.b1.setText("load more");
              
                  }
                  else
                   {
                      personViewHolder.question.setText(persons.get(i).name);
                      personViewHolder.personAge.setText(persons.get(i).age);
              
                       if(personViewHolder.check[i]==0)
                       {personViewHolder.upvote.setBackgroundResource(R.drawable.noupvote);
                       }
                       else
                       {
                           personViewHolder.upvote.setBackgroundResource(R.drawable.upvote);
              
                       }
              
                       personViewHolder.upvote.setOnClickListener(new View.OnClickListener() {
                           @Override
                           public void onClick(View v) {
                               if(personViewHolder.check[i]==0)
                               {personViewHolder.check[i]=1;
                                   personViewHolder.upvote.setBackgroundResource(R.drawable.upvote);
              
              
                               }
                               else
                               {personViewHolder.check[i]=0;
                                   personViewHolder.upvote.setBackgroundResource(R.drawable.noupvote);
              
                               }
              
              
                           }
                       });
                      // personViewHolder.personPhoto.setImageResource(persons.get(i).photoId);
                  }
              
              }
              

              【讨论】:

                【解决方案14】:

                我也遇到了同样的问题。当我在我的 recyclerView 中单击项目的切换按钮时,选中的切换按钮出现在每 10 个项目中(例如,如果在索引为 0 的项目中单击它,那么索引为 9、18、27 的项目也会被单击)。首先,我在 onBindViewHolder 中的代码是:

                if (newsItems.get(position).getBookmark() == 1) {
                            holder.getToggleButtonBookmark().setChecked(true);
                        }
                

                但后来我添加了 Else 语句

                if (newsItems.get(position).getBookmark() == 1) {
                            holder.getToggleButtonBookmark().setChecked(true);
                //else statement prevents auto toggling
                        } else{
                            holder.getToggleButtonBookmark().setChecked(false);
                        }
                

                问题解决了

                【讨论】:

                • 谢谢。如果在回收视图相同的视图时默认选中,其他部分将清除复选框。
                【解决方案15】:

                好的,这里有很多答案这里我会发布我的代码,我会简单地解释我做了什么......它可能会帮助像我这样的小辈:D。

                1- 目标:

                我们将创建一个包含CheckBoxRadioButtonRecyclerView 列表,如下所示:

                2- 模型类

                public class ModelClass {
                private String time;
                private boolean checked;
                private boolean free;
                private boolean paid;
                
                public TherapistScheduleModel(String time, boolean checked, boolean free, boolean paid) {
                    this.time = time;
                    this.checked = checked;
                    this.free = free;
                    this.paid = paid;
                }
                
                public boolean isFree() {
                    return free;
                }
                
                public void setFree(boolean free) {
                    this.free = free;
                }
                
                public boolean isPaid() {
                    return paid;
                }
                
                public void setPaid(boolean paid) {
                    this.paid = paid;
                }
                
                public String getTime() {
                    return time;
                }
                
                public void setTime(String time) {
                    this.time = time;
                }
                
                public boolean getChecked() {
                    return checked;
                }
                
                public void setChecked(boolean checked) {
                    this.checked= checked;
                }
                }
                

                3-我的神奇适配器

                public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
                private Context context;
                private ListAllListeners listAllListeners;
                private ArrayList<ModelClass> mDataList;
                
                public MyAdapter(Context context, ArrayList<ModelClass> mDataList,
                                             ListAllListeners listAllListeners) {
                    this.mDataList = mDataList;
                    this.listAllListeners = listAllListeners;
                    this.context = context;
                }
                
                @NonNull
                @Override
                public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
                    LayoutInflater inflater = LayoutInflater.from(parent.getContext());
                    View view = inflater.inflate(R.layout.single_view, parent, false);
                    return new MyViewHolder(view);
                }
                
                @Override
                public int getItemCount() {
                    if (mDataList != null)
                        return mDataList.size();
                    else
                        return 0;
                }
                
                @Override
                public void onBindViewHolder(@NonNull final MyViewHolder holder, final int position) {
                     //important to:
                    //setOnCheckedChangeListener to 'null'
                    holder.checkBoxTime.setOnCheckedChangeListener(null);
                    holder.freeRB.setOnCheckedChangeListener(null);
                    holder.paidRB.setOnCheckedChangeListener(null);
                
                    //Check Box
                            holder.checkBoxTime.setText(mDataList.get(holder.getAdapterPosition()).getTime());
                    //here we check if the item is checked or not from the model.
                    if(mDataList.get(holder.getAdapterPosition()).getChecked())
                        holder.checkBoxTime.setChecked(true);
                    else
                        holder.checkBoxTime.setChecked(false);
                
                    holder.checkBoxTime.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                        @Override
                        public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                            if (b) {
                                mDataList.get(holder.getAdapterPosition()).setChecked(true);
                                listAllListeners.onItemCheck(holder.checkBoxTime.getText().toString(), holder.getAdapterPosition());
                            }
                            else {
                                mDataList.get(holder.getAdapterPosition()).setChecked(false);
                                listAllListeners.onItemUncheck(holder.checkBoxTime.getText().toString(), holder.getAdapterPosition());
                            }
                        }
                    });
                
                    //Radio Buttons
                
                    if(mDataList.get(holder.getAdapterPosition()).isFree())
                        holder.freeRB.setChecked(true);
                    else
                        holder.freeRB.setChecked(false);
                    holder.freeRB.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                        @Override
                        public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                            if (b) {
                                mDataList.get(holder.getAdapterPosition()).setFree(true);
                                listAllListeners.onFreeCheck(holder.freeRB.getText().toString(), holder.getAdapterPosition());
                            } else {
                                mDataList.get(holder.getAdapterPosition()).setFree(false);
                                listAllListeners.onFreeUncheck(holder.freeRB.getText().toString(), holder.getAdapterPosition());
                            }
                        }
                    });
                
                   //***and so on to paidRB***
                
                }//end onBindViewHolder()
                
                public interface ListAllListeners {
                //here is a list of clicked listeners to use them as you want ;).
                //you can get a list of checked or unChecked of all 
                        void onItemCheck(String checkBoxName, int position);
                        void onItemUncheck(String checkBoxName, int position);
                        void onFreeCheck(String name, int pos);
                        void onFreeUncheck(String name, int pos);
                        void onPaidCheck(String name, int pos);
                        void onPaidUncheck(String name, int pos);
                    }
                
                    class MyViewHolder extends RecyclerView.ViewHolder {
                
                        CheckBox checkBoxTime;
                        RadioButton freeRB, paidRB;
                
                        MyViewHolder(View itemView) {
                            super(itemView);
                            checkBoxTime = itemView.findViewById(R.id.timeCheckBox);
                            freeRB = itemView.findViewById(R.id.freeRadioBtn);
                            paidRB = itemView.findViewById(R.id.paidRadioBtn);
                        }
                    }//end class MyViewHolder
                
                    }//end class
                

                3- 在活动中你会得到这样的东西:

                myAdapter= new MyAdapter(getActivity().getApplicationContext(), mDataList,
                                new MyAdapter.ListAllListeners() {
                
                                    @Override
                                    public void onItemCheck(String checkBoxName, int position) {
                                        Toast.makeText(getActivity(), "" + checkBoxName + "  " + position, Toast.LENGTH_SHORT).show();
                                    }
                
                                    @Override
                                    public void onItemUncheck(String checkBoxName, int position) {
                                        Toast.makeText(getActivity(), "" + checkBoxName + "  " + position, Toast.LENGTH_SHORT).show();
                                    }
                
                                    @Override
                                    public void onFreeCheck(String name, int position) {
                
                                        Toast.makeText(getActivity(), "" + name + "  " + position, Toast.LENGTH_SHORT).show();
                                    }
                
                                    @Override
                                    public void onFreeUncheck(String name, int position) {
                
                                        Toast.makeText(getActivity(), "" + name + "  " + position, Toast.LENGTH_SHORT).show();
                                    }
                
                                    @Override
                                    public void onPaidCheck(String name, int position) {
                
                                        Toast.makeText(getActivity(), "" + name + "  " + position, Toast.LENGTH_SHORT).show();
                                    }
                
                                    @Override
                                    public void onPaidUncheck(String name, int position) {
                
                                        Toast.makeText(getActivity(), "" + name + "  " + position, Toast.LENGTH_SHORT).show();
                                    }
                                });
                

                【讨论】:

                  【解决方案16】:

                  这是一个对我有用的 Kotlin 解决方案

                  class SpecialtyFragmentRecyclerAdapter : RecyclerView.Adapter<SpecialtyFragmentRecyclerAdapter.SpecialtyViewHolder>(){
                  
                      private var _specialtySet = mutableSetOf(
                          "Yoruba Attires",
                          "Hausa Attires",
                          "Senator",
                          "Embroidery",
                          "Africa Fashion",
                          "School Uniform",
                          "Military and Para-Military Uniforms",
                          "Igbo Attires",
                          "South-South Attires",
                          "Kaftans",
                          "Contemporary",
                          "Western Fashion",
                          "Caps"
                      ).toSortedSet()
                  
                      val specialtySet: Set<String> get() = _specialtySet
                      val savedSpecialtySet = mutableSetOf<String>().toSortedSet()
                  
                      inner class SpecialtyViewHolder(
                          var itemBinding: SpecialtyFragmentRecyclerItemBinding
                      ) :
                          RecyclerView.ViewHolder(itemBinding.root) {
                  
                          fun bind(specialty: String) = with(itemBinding) {
                  
                              specialtyFragmentYorubaAttiresCheckBox.text = specialty
                              specialtyFragmentYorubaAttiresCheckBox.isChecked = savedSpecialtySet.contains(specialty)
                  
                       //AREA OF INTEREST
                  
                       //Either Setting the CheckBox onCheckChangeListener to works
                       specialtyFragmentYorubaAttiresCheckBox.setOnCheckedChangeListener(null)
                  
                       specialtyFragmentYorubaAttiresCheckBox.setOnCheckedChangeListener(
                                  CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
                                      if (buttonView.isPressed) { //OR this Also Works {Check if the Button is Pressed Before verifying the Checked State}
                                          if (isChecked) {
                                              savedSpecialtySet.add(specialty) //Perform Your Operation for Checked State
                                          } else {
                                              savedSpecialtySet.remove(specialty) //Perform Your Operation for unChecked State
                                          }
                                      }
                                  }
                              )
                  
                          }
                      }
                  
                      override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SpecialtyViewHolder {
                          val viewBinding = SpecialtyFragmentRecyclerItemBinding
                              .inflate(LayoutInflater.from(parent.context), parent, false)
                          return SpecialtyViewHolder(viewBinding)
                      }
                  
                      override fun onBindViewHolder(holder: SpecialtyViewHolder, position: Int) {
                          val specialty = _specialtySet.elementAt(position)
                          holder.bind(specialty)
                      }
                  
                      override fun getItemCount(): Int {
                          return _specialtySet.size
                      }
                  
                      fun populateList(list: MutableList<String>) {
                          savedSpecialtySet.addAll(list)
                          _specialtySet.addAll(list)
                          notifyDataSetChanged()
                      }
                  
                      fun addNewSpecialty(specialty: String) {
                          _specialtySet.add(specialty.trim())
                          savedSpecialtySet.add(specialty.trim())
                          notifyDataSetChanged()
                      }
                  
                      fun removeSpecialty(element: String) {
                          _specialtySet.remove(element)
                          savedSpecialtySet.remove(element)
                          notifyDataSetChanged()
                      }
                  }
                  

                  【讨论】:

                    【解决方案17】:

                    公共类 TagYourDiseaseAdapter 扩展 RecyclerView.Adapter { 私有 ReCyclerViewItemClickListener mRecyclerViewItemClickListener; 私有上下文 mContext;

                    List<Datum> deviceList = Collections.emptyList();
                    
                    /**
                     * Initialize the values
                     *
                     * @param context : context reference
                     * @param devices : data
                     */
                    
                    public TagYourDiseaseAdapter(Context context, List<Datum> devices,
                                                 ReCyclerViewItemClickListener mreCyclerViewItemClickListener) {
                        this.mContext = context;
                        this.deviceList = devices;
                        this.mRecyclerViewItemClickListener = mreCyclerViewItemClickListener;
                    }
                    
                    
                    /**
                     * @param parent   : parent ViewPgroup
                     * @param viewType : viewType
                     * @return ViewHolder
                     * <p>
                     * Inflate the Views
                     * Create the each views and Hold for Reuse
                     */
                    @Override
                    public TagYourDiseaseAdapter.OrderHistoryViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                    
                        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_tag_disease, parent, false);
                        TagYourDiseaseAdapter.OrderHistoryViewHolder myViewHolder = new TagYourDiseaseAdapter.OrderHistoryViewHolder(view);
                        return myViewHolder;
                    }
                    
                    
                    /**
                     * @param holder   :view Holder
                     * @param position : position of each Row
                     *                 set the values to the views
                     */
                    @Override
                    public void onBindViewHolder(final TagYourDiseaseAdapter.OrderHistoryViewHolder holder, final int position) {
                        Picasso.with(mContext).load(deviceList.get(position).getIconUrl()).into(holder.document);
                        holder.name.setText(deviceList.get(position).getDiseaseName());
                    
                        holder.radioButton.setOnCheckedChangeListener(null);
                        holder.radioButton.setChecked(deviceList.get(position).isChecked());
                    
                        //if true, your checkbox will be selected, else unselected
                        //holder.radioButton.setChecked(objIncome.isSelected());
                    
                        holder.radioButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                            @Override
                            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                                deviceList.get(position).setChecked(isChecked);
                            }
                        });
                    
                    
                    }
                    
                    @Override
                    public int getItemCount() {
                        return deviceList.size();
                    }
                    
                    
                    /**
                     * Create The view First Time and hold for reuse
                     * View Holder for Create and Hold the view for ReUse the views instead of create again
                     * Initialize the views
                     */
                    
                    public class OrderHistoryViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
                        ImageView document;
                        TextView name;
                        CheckBox radioButton;
                    
                        public OrderHistoryViewHolder(View itemView) {
                            super(itemView);
                            document = itemView.findViewById(R.id.img_tag);
                            name = itemView.findViewById(R.id.text_tag_name);
                            radioButton = itemView.findViewById(R.id.rdBtn_tag_disease);
                            radioButton.setOnClickListener(this);
                            //this.setIsRecyclable(false);
                        }
                    
                    
                        @Override
                        public void onClick(View view) {
                            mRecyclerViewItemClickListener.onItemClickListener(this.getAdapterPosition(), view);
                        }
                    }
                    

                    }

                    【讨论】:

                      【解决方案18】:

                      当使用 setOnCheckedChangeListener 而不是使用 setObClickListener 时会发生这种情况,并且在里面只做这个简单的处理:

                         if (list.get(position).isCheck())
                                  {
                                      list.get(position).setCheck(false);
                                  }
                                  else
                                  {
                                      list.get(position).setCheck(true);
                                  }
                      

                      注意:在您的列表模型中添加一个名为 check 的布尔变量并为此设置 getter 和 setter,在上述情况下,我的是 setCheck 和 isCheck

                      希望对某人有所帮助+投票给这个答案

                      【讨论】:

                        【解决方案19】:

                        setItemViewCacheSize(int size) 添加到 recyclerview 并传递列表大小解决了我的问题。

                        我的代码:

                        mrecyclerview.setItemViewCacheSize(mOrderList.size());
                        mBinding.mrecyclerview.setAdapter(mAdapter);
                        

                        来源: https://stackoverflow.com/a/46951440/10459907

                        【讨论】:

                          【解决方案20】:

                          这是由于一次又一次地创建视图,最好的选择是在设置适配器之前清除缓存

                          recyclerview.setItemViewCacheSize(your array.size());
                          

                          【讨论】:

                            【解决方案21】:

                            完整示例
                            公共类 ChildAddressAdapter 扩展 RecyclerView.Adapter {

                            private Activity context;
                            private List<AddressDetail> addressDetailList;
                            private int selectedPosition = -1;
                            
                            public ChildAddressAdapter(Activity context, List<AddressDetail> addressDetailList) {
                                this.context = context;
                                this.addressDetailList = addressDetailList;
                            }
                            
                            @NonNull
                            @Override
                            public CartViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
                            
                                LayoutInflater inflater = LayoutInflater.from(context);
                                View myView = inflater.inflate(R.layout.address_layout, parent, false);
                                return new CartViewHolder(myView);
                            }
                            
                            @Override
                            public void onBindViewHolder(@NonNull CartViewHolder holder, int position) {
                            
                                holder.adress_checkbox.setOnClickListener(view -> {
                                    selectedPosition = holder.getAdapterPosition();
                                    notifyDataSetChanged();
                                });
                            
                                if (selectedPosition==position){
                                    holder.adress_checkbox.setChecked(true);
                                }
                                else {
                                    holder.adress_checkbox.setChecked(false);
                                }
                            
                            
                            }
                            
                            @Override
                            public int getItemCount() {
                                return  addressDetailList.size();
                            }
                            
                            class CartViewHolder extends RecyclerView.ViewHolder
                            {
                                TextView address_text,address_tag;
                                CheckBox adress_checkbox;
                            
                                CartViewHolder(View itemView) {
                                    super(itemView);
                                    address_text = itemView.findViewById(R.id.address_text);
                                    address_tag = itemView.findViewById(R.id.address_tag);
                                    adress_checkbox = itemView.findViewById(R.id.adress_checkbox);
                                }
                            }
                            

                            }

                            【讨论】:

                              【解决方案22】:

                              解决方案是选中复选框。需要存储这个单独的列表。并使用该列表填充回收站视图中的复选框。

                              你可以参考这个链接。

                              https://blog.oziomaogbe.com/2017/10/18/android-handling-checkbox-state-in-recycler-views.html

                              【讨论】:

                                【解决方案23】:

                                如果不晚;这实际上是 recyclerView 的一般问题。您可以将您的 recyclerView 放入嵌套的 Scroll 视图中,然后将一行代码添加到您的适配器。一切都完成了。

                                在您的活动或片段中;

                                 <androidx.core.widget.NestedScrollView
                                                    android:layout_width="match_parent"
                                                    android:layout_height="match_parent"
                                                    >
                                
                                                    <LinearLayout
                                                        android:layout_width="match_parent"
                                                        android:layout_height="wrap_content"
                                                        android:orientation="vertical">
                                
                                                        <androidx.recyclerview.widget.RecyclerView
                                                            android:id="@+id/recyclerView"
                                                            android:layout_width="match_parent"
                                                            android:layout_height="match_parent"
                                                            />
                                                    </LinearLayout>
                                
                                                </androidx.core.widget.NestedScrollView>
                                

                                并在您设置适配器的活动中添加此内容。

                                
                                 ViewCompat.setNestedScrollingEnabled(recyclerView, false);
                                
                                 LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
                                 //your adapter code...
                                 recyclerView.setAdapter(textSearchAdapter);
                                
                                

                                【讨论】:

                                  【解决方案24】:

                                  对我有用的是在视图将被回收时使 viewHolder 上的侦听器无效 (onViewRecycled):

                                   override fun onViewRecycled(holder: AttendeeViewHolder) {
                                              super.onViewRecycled(holder)
                                              holder.itemView.hasArrived.setOnCheckedChangeListener(null);
                                              holder.itemView.edit.setOnClickListener { null }
                                          }
                                  

                                  【讨论】:

                                    猜你喜欢
                                    • 2016-10-08
                                    • 1970-01-01
                                    • 2016-03-18
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 2021-08-15
                                    相关资源
                                    最近更新 更多