ListView使用ViewHolder出现复用冲突的原因:
因为复用的原理就是 行布局中 子控件对象的复用:
1.滑动过程中将已完全不显示的控件用行布局的setTag方法保存到ViewHolder中,保存的对象用于下一个即将显示的控件
2.下一个即将显示的控件没有findViewById,而是直接使用了行布局getTag()方法返回的对象(返回的对象不一定)
3.行布局存在CheckBox时,比如ListView适配器的getView()方法如下
/*
* 该方法在适配器生成行布局的时候会被回调(控件从完全不显示 -> 显示)
*/
@Override public View getView(final int position, View convertView, ViewGroup parent) { ViewHolder holder = null; // 下面要用到,先创建一个 if (convertView == null) { // 若界面能显示6行数据,则前6次ListView加载行布局的时候convertView都是null convertView = LayoutInflater.from(context).inflate(R.layout.item_lv, parent, false); // - - null就创建一个 holder = new ViewHolder(convertView); // holder对象就是用于保存行布局的子控件的 convertView.setTag(holder); // 将convertView保存到holder holder.cb.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { checked[position] = ! checked[position]; // 一个数组,用来保存所有行布局的checked属性 } }); }else { holder = (ViewHolder) convertView.getTag(); // 若行布局不为null,则应该复用子控件 } // 设置数据 holder.tv.setText("hahahah1" + position); holder.cb.setChecked(checked[position]); //如果没有这一行 若checkbox1被选中了,然后滑动后从页面消失了,再回来 checkbox1 的选中状态会消失 return convertView; }
如果使用我的方法
需要注意的是上面CheckBox设置的是点击监听,不能设置为OnCheckChangedListener,
...因为控件内部不知道哪里调用了setChecked方法,之前看到了,忘了是哪里了...回去查查资料