1,常用的写法,只展示Adapter,问题原因就在Adapter中
class Adapter1 extends BaseAdapter{
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final int index = position;
ViewHolder viewHolder;
if(convertView == null){
viewHolder = new ViewHolder();
convertView = LayoutInflater.from(ListViewCheckBox.this).inflate(R.layout.listview_checkbox_item, null);
viewHolder.layout = (LinearLayout)convertView.findViewById(R.id.layout);
viewHolder.textView = (TextView)convertView.findViewById(R.id.textView);
viewHolder.checkBox = (CheckBox)convertView.findViewById(R.id.checkBox);
convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder)convertView.getTag();
}
viewHolder.textView.setText(list.get(position).name);
if(list.get(position).type == A.TYPE_CHECKED){
viewHolder.checkBox.setChecked(true);
}else{
viewHolder.checkBox.setChecked(false);
}
/*点击checkBox所在行改变checkBox状态*/
/*final ViewHolder vv = viewHolder;
viewHolder.layout.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(vv.checkBox.isChecked()){
vv.checkBox.setChecked(false);
list.get(index).type = TYPE_CHECKED;
}else{
vv.checkBox.setChecked(true);
list.get(index).type = TYPE_NOCHECKED;
}
}
});*/
viewHolder.checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked){
list.get(index).type = A.TYPE_CHECKED;
}else{
list.get(index).type = A.TYPE_NOCHECKED;
}
}
});
return convertView;
}
}
class ViewHolder{
LinearLayout layout;
TextView textView;
CheckBox checkBox;
}
class A {
public static final int TYPE_CHECKED = 1;
public static final int TYPE_NOCHECKED = 0;
String name;
int type;
public A(String name,int type){
this.name = name;
this.type = type;
}
}
}
这时出现了混乱选中问题,为什么呢?
首先,我们使用了一个数组来存储每个CheckBox的状态,如果被选中,我们在setOnCheckedChangeListener 监听事件中的OnCheckChanged()方法中将状态修改为被选中,如果被取消选中,则改为被取消选中。
我们还使用了Convertview + ViewHolder来进行view的复用,提高listView的加载效率以及减少每次new一个View 的开销。这也是导致我们出现了混乱选中的根源所在。
下面来分析下到底是如何出现的混乱选中。
1,假设我们的convertview有着10个复用的View对象(这个好像会跟显示View时,一个屏幕能放下多少View相关,如果最多只能显示五个,那么只使用5个用来复用的View),那么当我们分别用完了这十个之后就会开始复用,比如说我的界面中有30个用ListView+CheckBox组成的选择题。
我们从其他地方点进ListView所在的Activity,ListView进行加载,那么前10个是没有问题的。假设第一个我们进行了选择,状态为Checked。当我们下滑,显示到第11个的时候,这个时候第11个viewItem会复用第一个item的View。
这时。当将这一个viewItem加载到ListView的第11个位置时,它的状态是Checked。通过从状态数组中读取第11个Item的选中状态时,发现我并没有选中第11个Item,这时就会将第11个Item设置为未选中。
一切看起来这么顺利!!!
但是!
当我们的第11个Item从复用的第一个ItemView的选中状态 到 从状态数组中读取的未选中状态,是经过了一次setOnCheckedChangeListener 选中变化事件的监听的。
而且!!
我们仔细看,我们的setOnCheckedChangeListener 监听事件的设置是写在了我们初始化item的选中状态之后的。
也就是说!!
这时候我们的setOnCheckedChangeListener 监听事件是在第一个ViewItem初始化时设置的那个监听事件。
这个时候,由于发生了选中状态的变化,由第一个Item的选中变化监听事件所监听到了,从而改变了第一个Item的状态。当滑动几次时,由于反复的在复用convertView,便出现了非常令人头疼的混乱选中。。!
解决办法:把添加监听器的方法加到初始化view中checkBox状态的代码之前即可
。这时监听器便不会混乱监听了。
完美~~~
class Adapter1 extends BaseAdapter{
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final int index = position;
ViewHolder viewHolder;
if(convertView == null){
viewHolder = new ViewHolder();
convertView = LayoutInflater.from(ListViewCheckBox.this).inflate(R.layout.listview_checkbox_item, null);
viewHolder.layout = (LinearLayout)convertView.findViewById(R.id.layout);
viewHolder.textView = (TextView)convertView.findViewById(R.id.textView);
viewHolder.checkBox = (CheckBox)convertView.findViewById(R.id.checkBox);
convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder)convertView.getTag();
}
viewHolder.checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked){
list.get(index).type = A.TYPE_CHECKED;
}else{
list.get(index).type = A.TYPE_NOCHECKED;
}
}
});
viewHolder.textView.setText(list.get(position).name);
if(list.get(position).type == A.TYPE_CHECKED){
viewHolder.checkBox.setChecked(true);
}else{
viewHolder.checkBox.setChecked(false);
}
return convertView;
}
}