ListView中CheckBox复用问题

作者: 小编 | 来源:发表于2016-09-08 16:17 被阅读699次

在开发类似购物车编辑功能时遇到了CheckBox选择状态复用问题。
一言不合先上图:


范例.png

写法一:

CheckBox checkBox = holder.getView(R.id.checkbox);
checkBox.setTag(position);
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
    }
});

很显然,我们并没有用代码去控制CheckBoxchecked状态,因此导致ListView滑动的时候复用了CheckBox。所以我们可以加入Map集合,控制CheckBox显示状态。key记录position或者唯一idvalue记录truefalse的状态。

写法二:

//注意:全局定义
private HashMap<Long, Boolean> checkedMap = new HashMap<>();

/*以下是Adapter中代码*/
CheckBox checkBox = holder.getView(R.id.checkbox);
if (checkedMap.containsKey(getItem(position).getRelationId()) 
    && checkedMap.get(getItem(position).getRelationId())) {    
    //如果Map中存在此消息,并且已选中    
        checkBox.setChecked(true);
    } else {    
        checkBox.setChecked(false);
    }
checkBox.setTag(position);
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        int tag = (int) buttonView.getTag();
        checkedMap.put(getItem(tag).getRelationId(), isChecked);
        notifyDataSetChanged();
    }
});

依照写法二我们可以在onCheckedChanged方法中设置Mapkeyvalue,然后调用notifyDataSetChanged()通知Adapter刷新状态。

然而并没有什么卵用


并无卵用.jpg

当我们给CheckBox设置不同状态以后,滑动ListView时,发现CheckBox的状态发生了错乱,通过断点调试,发现Map中的数据是在改变的,从而导致CheckBox状态错乱,而真正能修改Map的地方只有onCheckedChanged方法,果不其然,滚动竟然导致了onCheckedChanged方法执行。

那么问题来了,咋搞!!!

原来是代码顺序出现了问题,我们先设置了CheckBox状态,然后再去设置了状态改变监听器。由于状态的改变,导致onCheckedChanged方法执行。

写法三

checkBox.setTag(position);
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        int tag = (int) buttonView.getTag();
        checkedMap.put(getItem(tag).getRelationId(), isChecked);
        notifyDataSetChanged();
    }
});
if (checkedMap.containsKey(getItem(position).getRelationId())
        && checkedMap.get(getItem(position).getRelationId())) {
    //如果Map中存在此消息,并且已选中
    checkBox.setChecked(true);
} else {
    checkBox.setChecked(false);
}

搞定!
先去嘘嘘~

相关文章

网友评论

  • SiberianDante:实体类中增加一个Boolean和集合其实是一个道理的吧,刚好解决了我的复用错乱问题
  • 193c19cdca0f:这是治标不治本的方法,要个说没有理清适配器和ListView的关系(遇到复杂业务逻辑的item这种方式可能会麻烦,处理不好会导致其他问题),ListView本身不存在这样的bug,出现复用究其根本是在适配器的getView方法中主改变一个控件状态不是通过实体控制而是其他方式控制(比如你上面的方式)。你这里实际上实体里面就应该有个bool字段来记录CheckBox的状态,把每次监听器中的值赋值给实体即可,然后调用刷新方法。至于上面使用集合记录操作都是多余的。
    结论就是实体变化就刷新适配器,也应该严格这样使用。也许有时间可以看看源码知其所以然。
    小编:@Hello恒 谢谢指点。我觉得两种方式都可以了,假如说设置已读完,状态都要回归false,我可以将mapclear掉。如果实体就可能需要重新加载,或者遍历集合设置
  • Pan_大宝:是每次复用的时候,都会调用一次new CompoundButton.OnCheckedChangeListener() 吗?
    小编: @Pan_大宝 是checkedbox状态改变导致方法调用

本文标题:ListView中CheckBox复用问题

本文链接:https://www.haomeiwen.com/subject/wuisettx.html