@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其实也是继承了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一样使用。
package com.netease.na..weight;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import com.netease.common.core.utils.log.Logger;
/**
* 多行RadioGroup
*
* @author [email protected]
*/
public class MultiRadioGroup extends RadioGroup {
private static final String TAG = "MultiRadioGroup";
private OnCheckedChangeListener mOnCheckedChangeListener;
private int mCheckId = -1;
public MultiRadioGroup(Context context) {
super(context);
}
public MultiRadioGroup(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
mOnCheckedChangeListener = listener;
}
@Override
public void addView(final View child, int index, ViewGroup.LayoutParams params) {
if (child instanceof LinearLayout) {
int childCount = ((LinearLayout) child).getChildCount();
for (int i = 0; i < childCount; i++) {
View view = ((LinearLayout) child).getChildAt(i);
if (view instanceof RadioButton) {
final RadioButton button = (RadioButton) view;
button.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
mCheckId = button.getId();
button.setChecked(true);
checkRadioButton(button);
if (mOnCheckedChangeListener != null) {
mOnCheckedChangeListener.onCheckedChanged(MultiRadioGroup.this, button.getId());
}
return true;
}
});
}
}
}
super.addView(child, index, params);
}
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);
}
}
}
}
}
}
/**
* 用于获取选中位置button的id
*/
public int getCheckId() {
return mCheckId;
}
}