ListView中Checkbox选择混乱的三种解决方式
问题描述
ListView中checkbox点击混乱的问题,可采用如下三种较好的方式解决。
先看错误代码
public class MainActivity extends AppCompatActivity {
private WebView wv;
private Button btn;
private ListView lv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv = (ListView) findViewById(R.id.lv);
lv.setAdapter(new MyAdapter());
}
private class MyAdapter extends BaseAdapter {
private List<CheckBean> beans = new ArrayList<>();
public MyAdapter(){
for (int i = 0; i < 50; i++) {
CheckBean bean = new CheckBean();
bean.setName("check : " + i);
bean.setChecked(false);
beans.add(bean);
}
}
@Override
public int getCount() {
return 50;
}
@Override
public Object getItem(int i) {
return null;
}
@Override
public long getItemId(int i) {
return 0;
}
@Override
public View getView(final int i, View contentView, ViewGroup viewGroup) {
final int index = i;
ViewHolder holder = null;
if(contentView == null) {
contentView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.lv_item,viewGroup,false);
holder = new ViewHolder(contentView);
} else {
holder = (ViewHolder) contentView.getTag();
}
holder.checkBox.setChecked(beans.get(i).isChecked());
holder.tv.setText("position:" + i);
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
beans.get(i).setChecked(b);
}
});
return contentView;
}
}
private static class ViewHolder {
private TextView tv;
private CheckBox checkBox;
private View contentView;
public ViewHolder(View view) {
this.contentView = view;
tv = contentView.findViewById(R.id.tv);
checkBox = contentView.findViewById(R.id.cb);
contentView.setTag(this);
}
}
}
代码思路是在JavaBean中定义一个isCheck
的属性,滑动时根据此属性来判断选择状态,这样会造成一个问题:
当勾选第0个条目时,此时isCheck状态为true,滑动条目到新的条目会复用第一个条目,而此时OnCheckedChangeListener还未绑定新的条目,依然会调用第0个条目的回调,因此,当往回滑动时,第0个条目的isCheck
状态依然会变成false
。
第一种解决办法
将setOnCheckedChangeListener写在setCheck方法上面,这样每次item绑定的都是最新的条目:
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
beans.get(i).setChecked(b);
}
});
holder.checkBox.setChecked(beans.get(i).isChecked());
第二种解决办法
不用setOnCheckedChangeListener
,改用setOnClickListener
holder.checkBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
beans.get(i).setChecked(!beans.get(i).isChecked());
finalHolder.checkBox.setChecked(beans.get(i).isChecked());
}
});
第三种解决办法
这种解决办法类似于第二种,只是ListView内部已经早就帮我们考虑到了这种问题的出现,并给出了解决办法。
ListView内部为我们提供的一个保存选中状态的数据结构:
SparseBooleanArray mCheckStates;
还有相应的API:
getCheckedItemCount()
getCheckedItemPositions()
setItemChecked(int postion,boolean b)
1.在ListView初始化时选择模式:
lv = (ListView) findViewById(R.id.lv);
lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
lv.setAdapter(new MyAdapter());
2、在getView
方法中,这样写:
@Override
public View getView(final int postion, View convertView, ViewGroup viewGroup) {
if (convertView == null) {
convertView = View.inflate(MainActivity.this, R.layout.item, null);
}
final AppCompatCheckBox checkBox = (AppCompatCheckBox) convertView.findViewById(R.id.checkbox);
checkBox.setChecked(lv.isItemChecked(postion));
checkBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
lv.setItemChecked(postion,checkBox.isChecked());
}
});
return convertView;
}