文/程序員男神
前言
最近項(xiàng)目升級上線浅役,科室提出一個需求斩松,希望可以全選一次把項(xiàng)目確費(fèi)調(diào)伶唯,不需要一個個去確費(fèi)觉既。自己開發(fā)過程中發(fā)現(xiàn),每次選中之后乳幸,上下滑動就會出現(xiàn)選中錯亂的問題瞪讼,通過了解,這是Recyclerview的復(fù)用性質(zhì)導(dǎo)致的粹断。
項(xiàng)目效果
原理分析
原理:RecycleView具有復(fù)用性符欠,條目中的checkBox的選中狀態(tài)在上下滑動的時候可能會被復(fù)用而導(dǎo)致混亂;如果RecycleView條目中的checkBox都有相應(yīng)的數(shù)據(jù)源瓶埋,刷新的時候每個條目中的checkBox會賦予相應(yīng)的狀態(tài)希柿,也就不會發(fā)生混亂,相當(dāng)于適配器將數(shù)據(jù)源賦給指定的控件一樣养筒。
解決以上問題可以采取以下思路:
1曾撤、首先聲明一個map,用來存儲checkbox的狀態(tài)晕粪。
//用來記錄所有checkbox的狀態(tài)
private Map<Integer, Boolean> checkStatus = new HashMap<>();
2挤悉、循環(huán)數(shù)據(jù)源的集合,初始化checkbox的選中狀態(tài)巫湘。
private void initData() {
list = new ArrayList<String>();
for (int i = 0; i < 50; i++) {
list.add("CheckBox" + i);
}
initCheck(false);
}
//更改集合內(nèi)部存儲的狀態(tài)
public void initCheck(boolean flag) {
for (int i = 0; i < list.size(); i++) {
//更改指定位置的數(shù)據(jù)
checkStatus.put(i, flag);
}
}
3装悲、重寫Adapter的getView方法時,為每個checkbox添加事件響應(yīng)并記錄選擇狀態(tài)尚氛,通過獲取獲取狀態(tài)記錄值獲取所有選擇的checkbox值诀诊。
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, final int position) {
holder.checkBox.setText(list.get(position));
//清除監(jiān)聽器
holder.checkBox.setOnCheckedChangeListener(null);
//設(shè)置選中狀態(tài)
holder.checkBox.setChecked(checkStatus.get(position));
//再設(shè)置一次CheckBox的選中監(jiān)聽器,當(dāng)CheckBox的選中狀態(tài)發(fā)生改變時阅嘶,把改變后的狀態(tài)儲存在Map中
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
checkStatus.put(position, isChecked);
//check狀態(tài)一旦改變畏梆,保存的check值也要發(fā)生相應(yīng)的變化
}
});
}
完整的Adapter的代碼
/**
* 描述: adapter
* 作者|時間: djj on 2019/4/26 17:16
* 博客地址: http://www.reibang.com/u/dfbde65a03fc
*/
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private List<String> list;
private Context mContext;
//用來記錄所有checkbox的狀態(tài)
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();
}
//更改集合內(nèi)部存儲的狀態(tài)
public void initCheck(boolean flag) {
for (int i = 0; i < list.size(); i++) {
//更改指定位置的數(shù)據(jù)
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));
//清除監(jiān)聽器
holder.checkBox.setOnCheckedChangeListener(null);
//設(shè)置選中狀態(tài)
holder.checkBox.setChecked(checkStatus.get(position));
//再設(shè)置一次CheckBox的選中監(jiān)聽器,當(dāng)CheckBox的選中狀態(tài)發(fā)生改變時奈懒,把改變后的狀態(tài)儲存在Map中
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
checkStatus.put(position, isChecked);
//check狀態(tài)一旦改變奠涌,保存的check值也要發(fā)生相應(yīng)的變化
}
});
}
@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