radiogroup
一、简介
在开发某APP时,遇到这么一个问题:要使用radiogroup来实现单选框效果,但是item太多,要分成两行来显示。
一开始我心想,这不是很简单吗,在xml布局里设置RadioGroup的orientation值为vertical,里面嵌套一个水平布局的Linearlayout,然后把radiobutton给它一个一个摆上去不就完事儿咯~so easy的事情,万万没想到。。。。。。
什么鬼??? 为什么没有单选效果了???
这个问题让我百思不得其解,直到我看到了RadioGroup的源码
二、源码分析
@Override
public void addView(View child, int index, ViewGroup.layoutparams params) {
// 下面这行就是关键中的关键了
if (child instanceof RadioButton) {
final RadioButton button = (RadioButton) child;
if (button.isChecked()) {
mProtectFromCheckedChange = true;
if (mCheckedId != -1) {
setCheckedStateForView(mCheckedId, false);
}
mProtectFromCheckedChange = false;
setCheckedId(button.getId());
}
}
super.addView(child, index, params);
}
让我们看看关键的判断:if (child instanceof RadioButton)
难怪没有了单选效果,因为我们在RadioGroup里面还嵌套了一层LinearLayout,无法进到判断中的代码块。
既然我们已经知道了为什么多行RadioGroup会没有单选效果,那么解决的方法也就呼之欲出了
三、实现RadioGroup
方法一: RadioGroup其实也是继承了LinearLayout来实现的,那么我们定义两个水平布局的RadioGroup,分别摆放其中的RadioGroup,然后设置相应的点击事件不就可以了吗?
xml布局
<RadioGroup
Android:id="@+id/rg_one"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:orientation="horizontal">
<RadioButton
android:id="@+id/rb_problem_speed_up_ERROR"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/selector_radiobutton"
android:button="@null"
android:paddingStart="@dimen/dp_14"
android:paddingTop="@dimen/dp_6"
android:paddingEnd="@dimen/dp_14"
android:paddingBottom="@dimen/dp_6"
android:text="@string/speed_up_error"
android:textColor="@drawable/selector_radiobutton_text"
android:textSize="@dimen/sp_15" />
<RadioButton
android:id="@+id/rb_problem_error_code"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_10"
android:background="@drawable/selector_radiobutton"
android:button="@null"
android:paddingStart="@dimen/dp_14"
android:paddingTop="@dimen/dp_6"
android:paddingEnd="@dimen/dp_14"
android:paddingBottom="@dimen/dp_6"
android:text="@string/error_code"
android:textColor="@drawable/selector_radiobutton_text"
android:textSize="@dimen/sp_15" />
<RadioButton
android:id="@+id/rb_problem_charge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_10"
android:background="@drawable/selector_radiobutton"
android:button="@null"
android:paddingStart="@dimen/dp_14"
android:paddingTop="@dimen/dp_6"
android:paddingEnd="@dimen/dp_14"
android:paddingBottom="@dimen/dp_6"
android:text="@string/charge"
android:textColor="@drawable/selector_radiobutton_text"
android:textSize="@dimen/sp_15" />
</RadioGroup>
<RadioGroup
android:id="@+id/rg_two"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margintop="@dimen/dp_10">
<RadioButton
android:id="@+id/rb_problem_others"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/selector_radiobutton"
android:button="@null"
android:paddingStart="@dimen/dp_14"
android:paddingTop="@dimen/dp_6"
android:paddingEnd="@dimen/dp_14"
android:paddingBottom="@dimen/dp_6"
android:text="@string/others"
android:textColor="@drawable/selector_radiobutton_text"
android:textSize="@dimen/sp_15" />
</RadioGroup>
具体实现:
mGroupOne.setOnCheckedChangeListener(new OnMultiOneCheckChangeListener());
mGroupTwo.setOnCheckedChangeListener(new OnMultiTwoCheckChangeListener());
private class OnMultiOneCheckChangeListener implements RadioGroup.OnCheckedChangeListener {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
switch (checkedId) {
case R.id.rb_problem_speed_up_error:
if (mSpeedButton.isChecked()) {
mGroupTwo.clearCheck();
}
break;
case R.id.rb_problem_error_code:
if (mErrorButton.isChecked()) {
mGroupTwo.clearCheck();
}
break;
case R.id.rb_problem_charge:
if (mChargeButton.isChecked()) {
mGroupTwo.clearCheck();
}
break;
}
}
}
private class OnMultiTwoCheckChangeListener implements RadioGroup.OnCheckedChangeListener {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
switch (checkedId) {
case R.id.rb_problem_others:
if (mOthersButton.isChecked()) {
mGroupOne.clearCheck();
}
break;
}
}
}
为两个RadioGroup分别设置监听,如果点击了其中一个RadioGroup的子button,清空另一个RadioGroup的勾选。
使用这种方法有很大的缺陷:如果不是两行,而是n行,就需要n个RadioGroup,并为这n个RadioRroup都设置监听。而且,每个RadioGroup中的子button都要做相应的勾选,清除其他RadioGroup勾选的操作,显得繁琐,不具有通用性。
方法二: 重写上面的addView代码,通过遍历的方式获取RadioGourp中,以及其子布局中的所有RadioButton,然后做相应的设置。
@Override
public void addView(final View child, int index, ViewGroup.LayoutParams params) {
if (child instanceof ViewGroup) {
int childCount = ((ViewGroup) child).getChildCount();
for (int i = 0; i < childCount; i++) {
View view = ((ViewGroup) child).getChildAt(i);
if (view instanceof RadioButton) {
final RadioButton button = (RadioButton) view;
button.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, motionevent event) {
// 设置button为当前选项
button.setChecked(true);
// 这个方法下面会分析,用于取消其他项的勾选
checkRadioButton(button);
if (mOnCheckedChangeListener != null) {
mOnCheckedChangeListener.onCheckedChanged(MultiRadioGroup.this, button.getId());
}
return true;
}
});
}
}
}
super.addView(child, index, params);
}
其实也很简单,首先判断子view是不是ViewGroup,如果不是ViewGroup,直接调用原来的addView方法;如果是则遍历其中的子View,并设置Touch事件:设置当前button为勾选项,通过checkRadioButton方法,取消其他项的勾选。下面分析checkRadioButton方法。
private void checkRadioButton(RadioButton radioButton) {
View child;
int radioCount = getChildCount();
for (int i = 0; i < radioCount; i++) {
child = getChildAt(i);
if (child instanceof RadioButton) {
RadioButton button = (RadioButton) child;
if (button == radioButton) {
// do nothing
} else {
button.setChecked(false);
}
} else if (child instanceof LinearLayout) {
int childCount = ((LinearLayout) child).getChildCount();
for (int j = 0; j < childCount; j++) {
View view = ((LinearLayout) child).getChildAt(j);
if (view instanceof RadioButton) {
RadioButton button = (RadioButton) view;
if (button == radioButton) {
// do nothing
} else {
button.setChecked(false);
}
}
}
}
}
}
其实就是通过遍历判断RadioButton是不是当前勾选的RadioButton,如果不是,setChecked为false。自此,我们就实现了多行RadioGroup,使用的方法和普通的RadioGroup一样。
xml布局
<com.linjunyi.MultiRadioGroup
android:id="@+id/rg_problem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:orientation="vertical"
android:paddingStart="@dimen/dp_15"
android:paddingTop="@dimen/dp_10"
android:paddingEnd="@dimen/dp_0"
android:paddingBottom="@dimen/dp_20">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/dp_10"
android:text="@string/question_type"
android:textColor="@color/color_333333"
android:textSize="@dimen/sp_12" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RadioButton
android:id="@+id/rb_problem_speed_up_error"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/selector_radiobutton"
android:button="@null"
android:paddingStart="@dimen/dp_14"
android:paddingTop="@dimen/dp_6"
android:paddingEnd="@dimen/dp_14"
android:paddingBottom="@dimen/dp_6"
android:text="@string/speed_up_error"
android:textColor="@drawable/selector_radiobutton_text"
android:textSize="@dimen/sp_15" />
<RadioButton
android:id="@+id/rb_problem_error_code"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_10"
android:background="@drawable/selector_radiobutton"
android:button="@null"
android:paddingStart="@dimen/dp_14"
android:paddingTop="@dimen/dp_6"
android:paddingEnd="@dimen/dp_14"
android:paddingBottom="@dimen/dp_6"
android:text="@string/error_code"
android:textColor="@drawable/selector_radiobutton_text"
android:textSize="@dimen/sp_15" />
<RadioButton
android:id="@+id/rb_problem_charge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_10"
android:background="@drawable/selector_radiobutton"
android:button="@null"
android:paddingStart="@dimen/dp_14"
android:paddingTop="@dimen/dp_6"
android:paddingEnd="@dimen/dp_14"
android:paddingBottom="@dimen/dp_6"
android:text="@string/charge"
android:textColor="@drawable/selector_radiobutton_text"
android:textSize="@dimen/sp_15" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_10">
<RadioButton
android:id="@+id/rb_problem_others"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/selector_radiobutton"
android:button="@null"
android:paddingStart="@dimen/dp_14"
android:paddingTop="@dimen/dp_6"
android:paddingEnd="@dimen/dp_14"
android:paddingBottom="@dimen/dp_6"
android:text="@string/others"
android:textColor="@drawable/selector_radiobutton_text"
android:textSize="@dimen/sp_15" />
</LinearLayout>
</com.linjunyi.MultiRadioGroup>
四、总结
使用以上两种方法都能实现多行RadioGroup,但是第一种方法不具备通用性,一旦行数变多,或是其中RadioButton变多,都会让处理代码变得冗长繁琐。第二种方法通过自定义一个MultiRadioGroup,然后继承RadioGroup并重写其中的addView方法,不管有多少行,其中有多少RadioButton,都不需要额外的代码,可以像普通的RadioGroup一样使用。
文章最后发布于: 2019-05-14 15:01:53
相关阅读
获取手机品牌:phone_brand = (TextView) findViewById(R.id.mobile_phone_brand); String brand = android.os.Build.BRAND; phone
Android入门 Android平台架构 应用程序 这一层是应用层,是Google最开始时在Android系统中捆绑了一些核心应用程序。比如e-mail客户
1、不使用adb命令android studio是识别不出来海马玩模拟器的, 打开cmd,输入:adb connect 127.0.0.1:26944。如下: C:\Users\Admin
屏幕尺寸屏幕尺寸指屏幕的对角线的长度,单位是英寸,1英寸=2.54厘米(下面有图文介绍)比如常见的屏幕尺寸有2.4、2.8、3.5、3.7、4.2、5
统计 可以很方便的给我们的程序 带来很多的参考;可以直观的了解我们的产品在市场的使用情况:下面简单谈谈 友盟在项目中的使用:简单