Recyclerview中使用CheckBox的問題總結
文/程式設計師男神
前言
最近專案升級上線,科室提出一個需求,希望可以全選一次把專案確費調,不需要一個個去確費。自己開發過程中發現,每次選中之後,上下滑動就會出現選中錯亂的問題,通過了解,這是Recyclerview的複用性質導致的。

專案效果
原理分析
原理:RecycleView具有複用性,條目中的checkBox的選中狀態在上下滑動的時候可能會被複用而導致混亂;如果RecycleView條目中的checkBox都有相應的資料來源,重新整理的時候每個條目中的checkBox會賦予相應的狀態,也就不會發生混亂,相當於介面卡將資料來源賦給指定的控制元件一樣。
解決以上問題可以採取以下思路:
1、首先宣告一個map,用來儲存checkbox的狀態。
//用來記錄所有checkbox的狀態 private Map<Integer, Boolean> checkStatus = new HashMap<>();
2、迴圈資料來源的集合,初始化checkbox的選中狀態。
private void initData() { list = new ArrayList<String>(); for (int i = 0; i < 50; i++) { list.add("CheckBox" + i); } initCheck(false); } //更改集合內部儲存的狀態 public void initCheck(boolean flag) { for (int i = 0; i < list.size(); i++) { //更改指定位置的資料 checkStatus.put(i, flag); } }
3、重寫Adapter的getView方法時,為每個checkbox新增事件響應並記錄選擇狀態,通過獲取獲取狀態記錄值獲取所有選擇的checkbox值。
@Override public void onBindViewHolder(@NonNull MyViewHolder holder, final int position) { holder.checkBox.setText(list.get(position)); //清除監聽器 holder.checkBox.setOnCheckedChangeListener(null); //設定選中狀態 holder.checkBox.setChecked(checkStatus.get(position)); //再設定一次CheckBox的選中監聽器,當CheckBox的選中狀態發生改變時,把改變後的狀態儲存在Map中 holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { checkStatus.put(position, isChecked); //check狀態一旦改變,儲存的check值也要發生相應的變化 } }); }
完整的Adapter的程式碼
/** * 描述: adapter * 作者|時間: djj on 2019/4/26 17:16 * 部落格地址: http://www.jianshu.com/u/dfbde65a03fc */ public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> { private List<String> list; private Context mContext; //用來記錄所有checkbox的狀態 private Map<Integer, Boolean> checkStatus = new HashMap<>(); public MyAdapter(Context mContext) { this.mContext = mContext; initData(); } private void initData() { list = new ArrayList<String>(); for (int i = 0; i < 50; i++) { list.add("CheckBox" + i); } initCheck(false); } //全選 public void selectAll() { initCheck(true); notifyDataSetChanged(); } //全不選 public void unSelectAll() { initCheck(false); notifyDataSetChanged(); } //更改集合內部儲存的狀態 public void initCheck(boolean flag) { for (int i = 0; i < list.size(); i++) { //更改指定位置的資料 checkStatus.put(i, flag); } } @NonNull @Override public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(mContext).inflate(R.layout.item_recyclerview, parent, false); return new MyViewHolder(view); } @Override public void onBindViewHolder(@NonNull MyViewHolder holder, final int position) { holder.checkBox.setText(list.get(position)); //清除監聽器 holder.checkBox.setOnCheckedChangeListener(null); //設定選中狀態 holder.checkBox.setChecked(checkStatus.get(position)); //再設定一次CheckBox的選中監聽器,當CheckBox的選中狀態發生改變時,把改變後的狀態儲存在Map中 holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { checkStatus.put(position, isChecked); //check狀態一旦改變,儲存的check值也要發生相應的變化 } }); } @Override public int getItemCount() { if (list != null) { return list.size(); } return 0; } class MyViewHolder extends RecyclerView.ViewHolder { private CheckBox checkBox; public MyViewHolder(View itemView) { super(itemView); checkBox = itemView.findViewById(R.id.check_box); } } }
效果GIF圖
下面就是我們效果圖:

我們demo效果
完整的程式碼路徑,需要的請下載:
https://github.com/hellodonj/CheckBoxRecyclerView.git