Android中ListView内复选框状态获取异常:多行时失效
兄弟,你这个问题其实是ListView的视图复用机制在搞鬼!当列表行数超过屏幕可见数量时,那些滚出屏幕的item会被系统回收复用,这时候lst1.getChildAt(i)只能拿到当前屏幕上显示的那些item,不在视野里的你根本拿不到,所以遍历所有索引去取CheckBox自然就失效了。
下面给你一套靠谱的解决方案,核心思路是把选中状态和数据绑定在一起,而不是直接从视图里硬取:
1. 准备选中状态存储集合
我们用SparseBooleanArray来记录每个列表项的选中状态(比HashMap更适合索引类场景):
// 在你的Activity/Fragment里定义全局变量 private SparseBooleanArray selectedStates = new SparseBooleanArray();
2. 自定义Adapter,绑定状态与视图
ListView的Adapter是数据和视图的桥梁,我们要在这里处理CheckBox的状态更新和存储:
public class SpecialityAdapter extends ArrayAdapter<String> { private String[] mSpecialties; private SparseBooleanArray mSelectedStates; public SpecialityAdapter(Context context, String[] specialties, SparseBooleanArray selectedStates) { super(context, R.layout.your_list_item_layout, specialties); mSpecialties = specialties; mSelectedStates = selectedStates; } @Override public View getView(final int position, View convertView, ViewGroup parent) { ViewHolder holder; // 复用视图,避免重复创建 if (convertView == null) { convertView = LayoutInflater.from(getContext()).inflate(R.layout.your_list_item_layout, parent, false); holder = new ViewHolder(); holder.cbSpeciality = convertView.findViewById(R.id.cbSpeciality); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } // 根据存储的状态设置CheckBox的选中状态 holder.cbSpeciality.setChecked(mSelectedStates.get(position, false)); // 监听CheckBox点击,更新状态集合 holder.cbSpeciality.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { mSelectedStates.put(position, isChecked); } }); // 设置item文本 holder.cbSpeciality.setText(mSpecialties[position]); return convertView; } // ViewHolder优化,避免重复findViewById static class ViewHolder { CheckBox cbSpeciality; } }
3. 初始化ListView并获取选中项
在你的Activity里完成Adapter初始化,之后需要获取选中项时,直接遍历状态集合即可:
// 初始化ListView ListView lst1 = findViewById(R.id.lst1); selectedStates = new SparseBooleanArray(); SpecialityAdapter adapter = new SpecialityAdapter(this, specialties, selectedStates); lst1.setAdapter(adapter); // 比如点击按钮时获取所有选中项 public void collectSelectedItems() { for (int i = 0; i < specialties.length; i++) { if (selectedStates.get(i, false)) { Log.d("asdf", "选中的项:" + specialties[i]); // 这里处理你的itemSelectedNameJson逻辑 } } }
再啰嗦下为什么之前的方法不行
ListView的getChildAt(i)返回的是当前屏幕可见的第i个视图,而不是数据集合里的第i项。当列表很长时,大部分item视图已经被系统回收复用,你遍历specialties.length去取,要么拿到null,要么拿到复用的旧视图,自然就没法正确获取选中状态了。
内容的提问来源于stack exchange,提问作者MACMAN
相关产品推荐
相关产品推荐

