关于Android RadioGroup的check()方法

需求:
界面上写一个两行三列的单选radiobutton组设置应用背景图,如下图
在这里插入图片描述
实现方法:
1、使用原始的RadioGroup可以实现布局,一个RadioGroup里两个LinearLayout分开radiobutton,但是会导致选项无法互斥。
2、Google官方的做法是写两个RadioGroup,但是要动态监听。(http://stackoverflow.com/questions/10425569/radiogroup-with-two-columns-which-have-ten-radiobuttons)
3、自定义一个RadioGroup。
4、用好 android:layout_marginLeft 和android:layout_marginTop这两条属性,调整好radiobutton的间距实现出多行多列的界面效果。(https://blog.csdn.net/mrzhang_happy/article/details/48436105)

之前写这个的人选择了写两行RadioGroup来实现,代码如下:

@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
    int bgId = 0;
    switch (checkedId) {
        case R.id.setting_rb_rainbow:
            rgScreenBg2.check(-1);
            bgId = R.drawable.home_bg_rainbow;
            break;
        case R.id.setting_rb_indigo_blue:
            rgScreenBg2.check(-1);
            bgId = R.drawable.home_bg_indigo_blue;
            break;
        case R.id.setting_rb_black:
            rgScreenBg2.check(-1);
            bgId = R.drawable.home_bg_black;
            break;
        case R.id.setting_rb_red:
            rgScreenBg1.check(-1);
            bgId = R.drawable.home_bg_red;
            break;
        case R.id.setting_rb_blue:
            rgScreenBg1.check(-1);
            bgId = R.drawable.home_bg_blue;
            break;
        case R.id.setting_rb_green:
            rgScreenBg1.check(-1);
            bgId = R.drawable.home_bg_green;
            break;
        default:
            break;
    }
    if(bgId != 0) {
        AppPrefs.getInstance().setAppBackground(bgId);
        getActivity().getWindow()
                .setBackgroundDrawableResource(AppPrefs.getInstance().getAppBackground());
    }
}

实现逻辑是这样的,点击第一行的radiobutton时清除第二行的选中项rgScreenBg2.check(-1),反之点击第二行时就执行rgScreenBg1.check(-1)。但是出现一个bug,选中项在第一行时去点击第二行的选项时,没有显示选中效果,反之选中项在第二行时也一样。

调试后,根本原因在于RadioGroup.check(-1)方法的执行,RadioGroup.check(-1)源码内多次调用了onCheckedChanged方法(具体源码分析请参考https://blog.csdn.net/qq_32452623/article/details/80474487)。 文章里面说用setChecked() 替代 setChecked(),但是不适用于我自己的问题。

解决方法:
我分析了它的执行顺序,举例子现在选中项为黑色,点击绿色的选项。onCheckedChanged第一次触发执行
case R.id.setting_rb_green: 然后执行 rgScreenBg1.check(-1);,此时不往下执行而去触发第二次onCheckedChanged监听,
case R.id.setting_rb_black: 然后又执行 rgScreenBg2.check(-1);
所以出现了没有选中项的显示效果,但是虽然多次调用onCheckedChanged方法,但是最后一次的执行结果会是对的,具体可看源码分析。

个人使用心得:
1、onCheckedChanged 监听方法并不是监听radiobutton点击事件,这是一个常见误区,它只是RadioGroup中的radiobutton状态变化的监听。

/**
 * <p>Interface definition for a callback to be invoked when the checked
 * radio button changed in this group.</p>
 */
public interface OnCheckedChangeListener {
    /**
     * <p>Called when the checked radio button has changed. When the
     * selection is cleared, checkedId is -1.</p>
     *
     * @param group the group in which the checked radio button has changed
     * @param checkedId the unique identifier of the newly checked radio button
     */
    public void onCheckedChanged(RadioGroup group, @IdRes int checkedId);
}

2、我觉得这个也是谷歌当初的设计问题,并没有为这种多行多列单选的使用场景做一个特定的控件,而且RadioGroup本身也没有radiobutton点击的监听接口方法。
3、最后我在onCheckedChanged中加了个标记值isWrong解决了(骚操作),但是解决这个问题的根本方法,我建议还是选择自定义的RadioGroup比较好。

@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
    int bgId = 0;
    int index = 0;
    switch (checkedId) {
        case R.id.setting_rb_rainbow:
            if (!isWrong) {
                isWrong = true;
                rgScreenBg2.check(-1);
            }
            bgId = R.drawable.home_bg_rainbow;
            index = 0;
            break;
        case R.id.setting_rb_indigo_blue:
            if (!isWrong) {
                isWrong = true;
                rgScreenBg2.check(-1);
            }
            bgId = R.drawable.home_bg_indigo_blue;
            index = 1;
            break;
        case R.id.setting_rb_black:
            if (!isWrong) {
                isWrong = true;
                rgScreenBg2.check(-1);
            }
            bgId = R.drawable.home_bg_black;
            index = 2;
            break;
        case R.id.setting_rb_red:
            if (!isWrong) {
                isWrong = true;
                rgScreenBg1.check(-1);
            }
            bgId = R.drawable.home_bg_red;
            index = 3;
            break;
        case R.id.setting_rb_blue:
            if (!isWrong) {
                isWrong = true;
                rgScreenBg1.check(-1);
            }
            bgId = R.drawable.home_bg_blue;
            index = 4;
            break;
        case R.id.setting_rb_green:
            if (!isWrong) {
                isWrong = true;
                rgScreenBg1.check(-1);
            }
            bgId = R.drawable.home_bg_green;
            index = 5;
            break;
        default:
            break;
    }

    if (bgId != 0 && !isWrong) {
        AppPrefs.getInstance().setAppBackground(index);
        getActivity().getWindow()
                .setBackgroundDrawableResource(Constants.bgArray[index]);
    }
    isWrong = false;
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值