这是基于
@lostdev的解决方案和
RadioGroup
实现的解决方案。它是一个修改后的RadioGroup,可与嵌套在子布局中的RadioButton(或其他CompoundButton)一起使用。
import android.content.Context;
import android.os.Build;
import android.support.annotation.IdRes;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import java.util.concurrent.atomic.AtomicInteger;
public class RecursiveRadioGroup extends LinearLayout {
public interface OnCheckedChangeListener {
void onCheckedChanged(RecursiveRadioGroup group, @IdRes int checkedId);
}
private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
private CompoundButton checkedView;
private CompoundButton.OnCheckedChangeListener childOnCheckedChangeListener;
private boolean mProtectFromCheckedChange = false;
private OnCheckedChangeListener onCheckedChangeListener;
private PassThroughHierarchyChangeListener mPassThroughListener;
public RecursiveRadioGroup(Context context) {
super(context);
setOrientation(HORIZONTAL);
init();
}
public RecursiveRadioGroup(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public RecursiveRadioGroup(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
childOnCheckedChangeListener = new CheckedStateTracker();
mPassThroughListener = new PassThroughHierarchyChangeListener();
super.setOnHierarchyChangeListener(mPassThroughListener);
}
@Override
public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
mPassThroughListener.mOnHierarchyChangeListener = listener;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
if (checkedView != null) {
mProtectFromCheckedChange = true;
setCheckedStateForView(checkedView, true);
mProtectFromCheckedChange = false;
setCheckedView(checkedView);
}
}
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
parseChild(child);
super.addView(child, index, params);
}
private void parseChild(final View child) {
if (child instanceof CompoundButton) {
final CompoundButton checkable = (CompoundButton) child;
if (checkable.isChecked()) {
mProtectFromCheckedChange = true;
if (checkedView != null) {
setCheckedStateForView(checkedView, false);
}
mProtectFromCheckedChange = false;
setCheckedView(checkable);
}
} else if (child instanceof ViewGroup) {
parseChildren((ViewGroup) child);
}
}
private void parseChildren(final ViewGroup child) {
for (int i = 0; i < child.getChildCount(); i++) {
parseChild(child.getChildAt(i));
}
}
public void check(CompoundButton view) {
if(checkedView != null) {
setCheckedStateForView(checkedView, false);
}
if(view != null) {
setCheckedStateForView(view, true);
}
setCheckedView(view);
}
private void setCheckedView(CompoundButton view) {
checkedView = view;
if(onCheckedChangeListener != null) {
onCheckedChangeListener.onCheckedChanged(this, checkedView.getId());
}
}
private void setCheckedStateForView(View checkedView, boolean checked) {
if (checkedView != null && checkedView instanceof CompoundButton) {
((CompoundButton) checkedView).setChecked(checked);
}
}
@IdRes
public int getCheckedItemId() {
return checkedView.getId();
}
public CompoundButton getCheckedItem() {
return checkedView;
}
public void clearCheck() {
check(null);
}
public void setOnCheckedChangeListener(RecursiveRadioGroup.OnCheckedChangeListener listener) {
onCheckedChangeListener = listener;
}
public static int generateViewId() {
for (; ; ) {
final int result = sNextGeneratedId.get();
int newValue = result + 1;
if (newValue > 0x00FFFFFF) newValue = 1;
if (sNextGeneratedId.compareAndSet(result, newValue)) {
return result;
}
}
}
private class CheckedStateTracker implements CompoundButton.OnCheckedChangeListener {
@Override
public void onCheckedChanged(CompoundButton view, boolean b) {
if (mProtectFromCheckedChange) {
return;
}
mProtectFromCheckedChange = true;
if (checkedView != null) {
setCheckedStateForView(checkedView, false);
}
mProtectFromCheckedChange = false;
int id = view.getId();
setCheckedView(view);
}
}
private class PassThroughHierarchyChangeListener implements OnHierarchyChangeListener {
private OnHierarchyChangeListener mOnHierarchyChangeListener;
@Override
public void onChildViewAdded(View parent, View child) {
if (child instanceof CompoundButton) {
int id = child.getId();
if (id == View.NO_ID) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
child.setId(generateViewId());
} else {
child.setId(View.generateViewId());
}
}
((CompoundButton) child).setOnCheckedChangeListener(childOnCheckedChangeListener);
if (mOnHierarchyChangeListener != null) {
mOnHierarchyChangeListener.onChildViewAdded(parent, child);
}
} else if(child instanceof ViewGroup) {
for(int i = 0; i < ((ViewGroup) child).getChildCount(); i++) {
onChildViewAdded(child, ((ViewGroup) child).getChildAt(i));
}
}
}
@Override
public void onChildViewRemoved(View parent, View child) {
if (child instanceof RadioButton) {
((CompoundButton) child).setOnCheckedChangeListener(null);
}
if (mOnHierarchyChangeListener != null) {
mOnHierarchyChangeListener.onChildViewRemoved(parent, child);
}
}
}
}
您可以像使用常规RadioGroup
一样在布局中使用它,唯一的区别是它也适用于嵌套的RadioButton
视图:
<RecursiveRadioGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<RadioButton
android:id="@+id/rbNotEnoughProfileInfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Not enough profile information"/>
<RadioButton
android:id="@+id/rbNotAGoodFit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Not a good fit"/>
<RadioButton
android:id="@+id/rbDatesNoLongerAvailable"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Dates no longer available"/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical">
<RadioButton
android:id="@+id/rbOther"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Other"/>
<android.support.v7.widget.AppCompatEditText
android:id="@+id/etReason"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/tvMessageError"
android:textSize="15sp"
android:gravity="top|left"
android:hint="Tell us more"
android:padding="16dp"
android:background="@drawable/edit_text_multiline_background"/>
</LinearLayout>
</RecursiveRadioGroup>