[ANDROID] RadioButton RadioGroup 组合多重使用的问题

做一个单选表格

和一般的单选框不一样,这次要做一个单选的表格,有两排,这样:
在这里插入图片描述
因为RadioGroup是LinearLayout,所以这种两排只能选一个,需要两个RadioGroup,左边是一个RadioGroup包含几个RadioButton,右边是另一个RadioGroup。

为了两个RadioGroup每次只选中一个,于是做如下处理:

       mRadioGroupLeft.setOnCheckedChangeListener((group, checkedId) -> {
            if (checkedId != View.NO_ID) {
                mRadioGroupRight.clearCheck();
            }
        });
        mRadioGroupRight.setOnCheckedChangeListener((group, checkedId) -> {
            if (checkedId != View.NO_ID) {
                mRadioGroupLeft.clearCheck();
            }
        });

就是当一边的RadioGroup被点击check的时候,清除另一个的check状态。
但这样发现有一个问题:
1,先点了左边RadioButton,一切正常,如上图;
2,再点击右边任意一个RadioButton,结果,左边的RadioButton被清除了check状态,但右边被点击的RadioButton却没有被选中。就是两边的check都清空了。如下图:
在这里插入图片描述
3,这时,再次点击两边的任意RadioButton都又会正常check。


经过深入分析,如下办法可以达到我希望的效果:

        mRadioGroupLeft.setOnCheckedChangeListener((group, checkedId) -> {
            if (checkedId != View.NO_ID && !mIsClearing) {
                mIsClearing = true;
                mReason = ((RadioButton) group.findViewById(checkedId)).getText().toString();
                mRadioGroupRight.clearCheck();
                mIsClearing = false;
            }
        });
        mRadioGroupRight.setOnCheckedChangeListener((group, checkedId) -> {
            if (checkedId != View.NO_ID && !mIsClearing) {
                mIsClearing = true;
                mReason = ((RadioButton) findViewById(checkedId)).getText().toString();
                mRadioGroupLeft.clearCheck();
                mIsClearing = false;
            }
        });

就是自己设置一个标志,防止一次点击清除两边的check状态。
发生问题的大概流程:
1,右边被点击,为了清除掉左边的check状态会这样调用 mRadioGroupLeft.clearCheck();
2,这样会发生mRadioGroupLeft的OnCheckedChangeListener被触发,这样就会又调用mRadioGroupRight.clearCheck();
3,所以,相当于两边的check状态都被清空了;


再深入分析,为啥调用mRadioGroupLeft的clearCheck,导致OnCheckedChangeListener回调会被触发。
先把分析结果放出来:
RadioGroup.clearCheck -> RadioGroup.check -> RadioGroup.setCheckedStateForView -> RadioButton.setChecked -> RadioGroup.CheckedStateTracker.onCheckedChanged -> RadioGroup.setCheckedId -> RadioGroup.mOnCheckedChangeListener.onCheckedChanged 回调外部listener

这里进入的是mRadioGroupLeft的方法:

    public void clearCheck() {
        check(-1);
    }

    public void check(@IdRes int id) {
        // don't even bother
        if (id != -1 && (id == mCheckedId)) {
            return;
        }

        if (mCheckedId != -1) {// <= 这里肯定能进来,因为左边已经有button被选中,关键就是这里
            setCheckedStateForView(mCheckedId, false);
        }

        if (id != -1) {
            setCheckedStateForView(id, true);
        }

        setCheckedId(id);
    }

// 再看setCheckedStateForView方法:
    private void setCheckedStateForView(int viewId, boolean checked) {
        View checkedView = findViewById(viewId);
        if (checkedView != null && checkedView instanceof RadioButton) {
            ((RadioButton) checkedView).setChecked(checked);
        }
    }

进入RadioButton的setChecked方法:

    public void setChecked(boolean checked) {
        if (mChecked != checked) {
            ......//省略一堆代码
            mChecked = checked;
            if (mOnCheckedChangeListener != null) {
                mOnCheckedChangeListener.onCheckedChanged(this, mChecked);
            }
            if (mOnCheckedChangeWidgetListener != null) {// 这个callback是关键
                mOnCheckedChangeWidgetListener.onCheckedChanged(this, mChecked);
            }
            ......
        }
    }

可以看到,setChecked会回调onCheckedChanged并把当前的check状态带上。
这个回调是RadioGroup对每个RadioButton注册的回调,所以回到RadioGroup:

    private class CheckedStateTracker implements CompoundButton.OnCheckedChangeListener {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            ......//省略一堆代码
            int id = buttonView.getId();
            setCheckedId(id);
        }
    }

    private void setCheckedId(@IdRes int id) {
        mCheckedId = id;
        if (mOnCheckedChangeListener != null) {//这个就会回到我们注册的callback
            mOnCheckedChangeListener.onCheckedChanged(this, mCheckedId);
        }
        .......
    }

所以因为RadioGroup内部的listener收到按钮状态改变isChecked=false,然后就回调到外层我们自己注册的listener了。
这里可以看出一个问题,就是RadioGroup的按钮状态isChecked不管变成true还是false,都会触发回调。
但给外层的回调又没有带上isChecked的参数,导致外层没法直接通过回调参数判断过来的状态。如果要判断,还得调用getCheckedRadioButtonId()去对比一下,这也是一个解决方案。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值