Android 防止 ListView 中嵌套 CheckBox 时,CheckBox 选中状态错乱

时间:2022-03-13 19:45:17

场景:当ListView中嵌套CheckBox,在滑动过程中,遇到滑动过程中,CheckBox选中状态错乱。

分析:ListView在滑动过程中,每个item都需要调用getView(int position, View convertView, ViewGroup parent)方法,而这个方法传入的 convertView 是在屏幕滑动过程中不断复用的,以减少 item 重新创建的内存消耗。但同时由于 convertView 的复用,也造成了我们的 CheckBox 展示状态默认复用前的状态。我们平时在 ListView 中出现的滑动过程中图片加载 闪烁也是同理。

优化方案:

本文仅以 ListView 支持单选为例:

1. 在实体类中添加一个参数:

    public boolean is_Checked = false;

2. 在Adapter添加CheckBox状态监听

    // 默认选中下标
    private int index = -1;
    @Override
    protected View getView(final int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder = null;
        if (convertView == null) {
            viewHolder = new ViewHolder();
            convertView = mInflater.inflate(R.layout.item_related_fields_left, null);
            viewHolder.cbTitle = (CheckBox) convertView.findViewById(R.id.tv_relative_fields_tag);
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }
        CircleEntity circleEntity = mList.get(position);
        viewHolder.cbTitle.setText(circleEntity.name);

        viewHolder.cbTitle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                if (b){
                    if (index != -1 ){ //判断是否被选中
                        mList.get(index).is_Checked = false;
                    }
                    index = position; 
                    mList.get(index).is_Checked = true;
                    mIOnCurrentFragment.currentIndex(position);
                    notifyDataSetChanged();
                }else {
                    if (index == position) { // 禁止取消当前项
                        compoundButton.setChecked(true);
                    }
                }
            }
        });

        //无默认选中项时:默认选中第一个
        if (index == -1)
            index= position;

        if (index == position)
            viewHolder.cbTitle.setChecked(true);
        else
            viewHolder.cbTitle.setChecked(circleEntity.is_Checked);
        return convertView;
    }
    public class ViewHolder {
        public CheckBox cbTitle;
    }

此方案适用于商品选择标签,(ListView + Fragment) 进行左右联动的场景