Android Studio中ListView的CheckBox全选反选功能失效如何解决
原有代码问题汇总
- ViewHolder被错误声明为
static全局变量,会导致ListView滑动复用条目时控件状态互相覆盖,显示错乱 - getView方法的else分支获取Holder逻辑错误,误调用
convertView.getName(),应该调用convertView.getTag()获取之前存储的Holder实例 - CheckBox点击事件中获取绑定数据的逻辑错误:你已经给CheckBox设置了
holder.selected.setTag(dat),但点击事件里用cb.getName()拿数据,应该改为cb.getTag() - 条目赋值逻辑拼写错误:你声明的当前条目变量是
Data dat = dataList.get(position),但设置文本时误写为holder.name.setText(data.getName()),应该改为dat.getName() listView.setItemChecked()不生效的原因:该方法仅对ListView开启CHOICE_MODE_MULTIPLE、且条目根布局实现了Checkable接口的场景生效,你自定义布局里单独加的CheckBox不会响应这个系统方法,需要自己通过修改数据源驱动界面更新,你后续的修复思路是正确的。
修复后完整实现代码
1. MyCustomAdapter修正代码
private static class MyCustomAdapter extends ArrayAdapter<Data> { private LayoutInflater layoutInflater; public ArrayList<Data> dataList; // 不要加static,避免内存泄漏和数据错乱 public MyCustomAdapter(Context context, int textViewResourceId, List<Data> objects) { super(context, textViewResourceId, objects); layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); this.dataList = new ArrayList<>(); this.dataList.addAll(objects); } private static class ViewHolder { TextView name; CheckBox selected; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if (null == convertView) { convertView = layoutInflater.inflate(R.layout.simple_list_item_1, null); holder = new ViewHolder(); holder.name = convertView.findViewById(R.id.NAME); holder.selected = convertView.findViewById(R.id.checkBox1); convertView.setTag(holder); // 点击CheckBox同步更新数据源 holder.selected.setOnClickListener(v -> { CheckBox cb = (CheckBox) v ; Data d = (Data) cb.getTag(); d.setSelected(cb.isChecked()); }); } else { holder = (ViewHolder) convertView.getTag(); } Data dat = dataList.get(position); holder.name.setText(dat.getName()); holder.selected.setChecked(dat.isSelected()); holder.selected.setTag(dat); return convertView; } }
2. Data类修正代码
public class Data { String name = null; boolean selected = false; public Data(String name,boolean selected) { this.name = name; this.selected = selected; } public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean isSelected() { return selected; } public void setSelected(boolean selected) { this.selected = selected; } }
3. 全选/取消全选按钮逻辑修正代码
boolean isAllSelected = false; // 不要用无意义的flag命名,提高可读性 Button mBtnSelect = root.findViewById(R.id.selectbutoon); mBtnSelect.setOnClickListener(view -> { isAllSelected = !isAllSelected; // 修改所有条目的选中状态 for(Data dat : dataAdapter.dataList){ dat.setSelected(isAllSelected); } // 通知Adapter刷新所有条目 dataAdapter.notifyDataSetChanged(); // 可选:修改按钮文字提示 mBtnSelect.setText(isAllSelected ? "取消全选" : "全选"); });
补充优化建议
- 如果列表数据量很大,可以给ListView设置
setChoiceMode(ListView.CHOICE_MODE_MULTIPLE)配合SparseBooleanArray记录选中状态,性能会比遍历数据源更好 - 避免给Adapter、ViewHolder、数据源加static修饰符,容易造成内存泄漏和数据意外篡改
内容的提问来源于stack exchange,提问作者Su Myat Kyaw
相关产品推荐
相关产品推荐

