RecyclerView 為了提高效率,其內(nèi)部使用了Recycler回收機制,原理是將上方的 itemView 銜接下次使用,僅加載數(shù)據(jù),從而達(dá)到View的復(fù)用。
問題描述
項目中涉及 RecyclerView 中包含 CheckBox 時。
- 首先遇到是焦點問題,主要是CheckBox搶占了焦點,造成點擊事件無法響應(yīng)的問題。
- 其次遇到CheckBox多選時,滑動狀態(tài)錯亂問題
焦點解決方案
為父級元素設(shè)置 android:descendantFocusability
| 屬性值 | 作用 |
|---|---|
| beforeDescendants | viewgroup會優(yōu)先其子類控件而獲取到焦點 |
| afterDescendants | viewgroup只有當(dāng)其子類控件不需要獲取焦點時才獲取焦點 |
| blocksDescendants | viewgroup會覆蓋子類控件而直接獲得焦點 |
狀態(tài)錯亂解決方案
方案一
原理:使用SparseBooleanArray(少量數(shù)據(jù)比HashMap效率更高,原因是其key的類型為 int 型,相比HashMap少了封箱過程)存儲選中的狀態(tài)值,根據(jù)position獲取。
//存儲選中狀態(tài)
private SparseBooleanArray mCheckStates = new SparseBooleanArray();
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
holder.checkBox.setTag(position);
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> {
int poi = (int) v.getTag();
if (isChecked) {
mCheckStates.put(poi, true);
} else {
mCheckStates.delete(poi);
}
});
holder.checkBox.setChecked(mCheckStates.get(position));
}
/** 設(shè)置全部選中否 */
public void setSelectAll(boolean selectAll) {
if (list != null) {
for (int i = 0; i < list.size(); i++) {
mCheckStates.put(i, selectAll);
}
notifyDataSetChanged();
}
}
方案二
原理:將CheckBox 的OnCheckedChangeListener 置空(因為當(dāng)view滑出致checkbox 的可視范圍時,OnCheckedChangeListener事件會被觸發(fā)),重新設(shè)置OnCheckedChangeListener事件。
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
holder.checkBox.setOnCheckedChangeListener(null);
holder.checkBox.setChecked(data.isSelect());
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> data.setSelect(isChecked));
holder.item.setOnClickListener(v -> {
data.setSelect(!holder.checkBox.isChecked());
holder.checkBox.setChecked(data.isSelect());
});
}
/** 設(shè)置全部選中否 */
public void setSelectAll(boolean selectAll) {
if (list != null) {
for (int i = 0; i < list.size(); i++) {
list.get(i).setSelect(selectAll);
}
notifyDataSetChanged();
}
}
注:以上便是RecyclerView和CheckBox的坑,具體使用哪個方案可根據(jù)實際問題選擇。