mar*_*f73 84 android radio-group radio-button android-linearlayout
我想知道是否有可能将每个单独RadioButton
的组合在一起,RadioGroup
保持相同的结构.我的结构看起来像这样:
如你所见,现在每个人RadioButton
都是不同的孩子LinearLayout
.我尝试使用下面的结构,但它不起作用:
Sco*_*ggs 44
似乎Google/Android的优秀人员认为,当您使用RadioButtons时,您不需要Android UI /布局系统的其他方面带来的灵活性.简单地说:他们不希望你嵌套布局和单选按钮.叹.
所以你必须解决这个问题.这意味着您必须自己实现单选按钮.
这真的不太难.在你的onCreate()中,用你自己的onClick()设置你的RadioButtons,这样当它们被激活时,它们setChecked(true)并对其他按钮执行相反的操作.例如:
class FooActivity {
RadioButton m_one, m_two, m_three;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
m_one = (RadioButton) findViewById(R.id.first_radio_button);
m_two = (RadioButton) findViewById(R.id.second_radio_button);
m_three = (RadioButton) findViewById(R.id.third_radio_button);
m_one.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
m_one.setChecked(true);
m_two.setChecked(false);
m_three.setChecked(false);
}
});
m_two.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
m_one.setChecked(false);
m_two.setChecked(true);
m_three.setChecked(false);
}
});
m_three.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
m_one.setChecked(false);
m_two.setChecked(false);
m_three.setChecked(true);
}
});
...
} // onCreate()
}
Run Code Online (Sandbox Code Playgroud)
是的,我知道 - 老派.但它的确有效.祝好运!
小智 27
使用我创建的这个类.它将在您的层次结构中找到所有可检查的子项.
import java.util.ArrayList;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Checkable;
import android.widget.LinearLayout;
public class MyRadioGroup extends LinearLayout {
private ArrayList<View> mCheckables = new ArrayList<View>();
public MyRadioGroup(Context context) {
super(context);
}
public MyRadioGroup(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyRadioGroup(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public void addView(View child, int index,
android.view.ViewGroup.LayoutParams params) {
super.addView(child, index, params);
parseChild(child);
}
public void parseChild(final View child)
{
if(child instanceof Checkable)
{
mCheckables.add(child);
child.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
for(int i = 0; i < mCheckables.size();i++)
{
Checkable view = (Checkable) mCheckables.get(i);
if(view == v)
{
((Checkable)view).setChecked(true);
}
else
{
((Checkable)view).setChecked(false);
}
}
}
});
}
else if(child instanceof ViewGroup)
{
parseChildren((ViewGroup)child);
}
}
public void parseChildren(final ViewGroup child)
{
for (int i = 0; i < child.getChildCount();i++)
{
parseChild(child.getChildAt(i));
}
}
}
Run Code Online (Sandbox Code Playgroud)
inf*_*net 17
好吧,我写了这个简单的课程.
只需像这样使用它:
// add any number of RadioButton resource IDs here
GRadioGroup gr = new GRadioGroup(this,
R.id.radioButton1, R.id.radioButton2, R.id.radioButton3);
Run Code Online (Sandbox Code Playgroud)
要么
GRadioGroup gr = new GRadioGroup(rb1, rb2, rb3);
// where RadioButton rb1 = (RadioButton) findViewById(R.id.radioButton1);
// etc.
Run Code Online (Sandbox Code Playgroud)
例如,您可以在Activity的onCreate()中调用它.无论RadioButton
您点击哪一个,其他都将取消选中.此外,没有问题,如果某些RadioButtons
内部RadioGroup
或某些内部.
这是班级:
package pl.infografnet.GClasses;
import java.util.ArrayList;
import java.util.List;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewParent;
import android.widget.RadioButton;
import android.widget.RadioGroup;
public class GRadioGroup {
List<RadioButton> radios = new ArrayList<RadioButton>();
/**
* Constructor, which allows you to pass number of RadioButton instances,
* making a group.
*
* @param radios
* One RadioButton or more.
*/
public GRadioGroup(RadioButton... radios) {
super();
for (RadioButton rb : radios) {
this.radios.add(rb);
rb.setOnClickListener(onClick);
}
}
/**
* Constructor, which allows you to pass number of RadioButtons
* represented by resource IDs, making a group.
*
* @param activity
* Current View (or Activity) to which those RadioButtons
* belong.
* @param radiosIDs
* One RadioButton or more.
*/
public GRadioGroup(View activity, int... radiosIDs) {
super();
for (int radioButtonID : radiosIDs) {
RadioButton rb = (RadioButton)activity.findViewById(radioButtonID);
if (rb != null) {
this.radios.add(rb);
rb.setOnClickListener(onClick);
}
}
}
/**
* This occurs everytime when one of RadioButtons is clicked,
* and deselects all others in the group.
*/
OnClickListener onClick = new OnClickListener() {
@Override
public void onClick(View v) {
// let's deselect all radios in group
for (RadioButton rb : radios) {
ViewParent p = rb.getParent();
if (p.getClass().equals(RadioGroup.class)) {
// if RadioButton belongs to RadioGroup,
// then deselect all radios in it
RadioGroup rg = (RadioGroup) p;
rg.clearCheck();
} else {
// if RadioButton DOES NOT belong to RadioGroup,
// just deselect it
rb.setChecked(false);
}
}
// now let's select currently clicked RadioButton
if (v.getClass().equals(RadioButton.class)) {
RadioButton rb = (RadioButton) v;
rb.setChecked(true);
}
}
};
}
Run Code Online (Sandbox Code Playgroud)
这是我基于@lostdev解决方案和实现的解决方案RadioGroup
.它是一个RadioGroup,经过修改后可以与嵌套在子布局中的RadioButtons(或其他CompoundButtons)一起使用.
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;
/**
* This class is a replacement for android RadioGroup - it supports
* child layouts which standard RadioGroup doesn't.
*/
public class RecursiveRadioGroup extends LinearLayout {
public interface OnCheckedChangeListener {
void onCheckedChanged(RecursiveRadioGroup group, @IdRes int checkedId);
}
/**
* For generating unique view IDs on API < 17 with {@link #generateViewId()}.
*/
private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
private CompoundButton checkedView;
private CompoundButton.OnCheckedChangeListener childOnCheckedChangeListener;
/**
* When this flag is true, onCheckedChangeListener discards events.
*/
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();
// checks the appropriate radio button as requested in the XML file
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));
}
}
/**
* <p>Sets the selection to the radio button whose identifier is passed in
* parameter. Using -1 as the selection identifier clears the selection;
* such an operation is equivalent to invoking {@link #clearCheck()}.</p>
*
* @param view the radio button to select in this group
* @see #getCheckedItemId()
* @see #clearCheck()
*/
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);
}
}
/**
* <p>Returns the identifier of the selected radio button in this group.
* Upon empty selection, the returned value is -1.</p>
*
* @return the unique id of the selected radio button in this group
* @attr ref android.R.styleable#RadioGroup_checkedButton
* @see #check(CompoundButton)
* @see #clearCheck()
*/
@IdRes
public int getCheckedItemId() {
return checkedView.getId();
}
public CompoundButton getCheckedItem() {
return checkedView;
}
/**
* <p>Clears the selection. When the selection is cleared, no radio button
* in this group is selected and {@link #getCheckedItemId()} returns
* null.</p>
*
* @see #check(CompoundButton)
* @see #getCheckedItemId()
*/
public void clearCheck() {
check(null);
}
/**
* <p>Register a callback to be invoked when the checked radio button
* changes in this group.</p>
*
* @param listener the callback to call on checked state change
*/
public void setOnCheckedChangeListener(RecursiveRadioGroup.OnCheckedChangeListener listener) {
onCheckedChangeListener = listener;
}
/**
* Generate a value suitable for use in {@link #setId(int)}.
* This value will not collide with ID values generated at build time by aapt for R.id.
*
* @return a generated ID value
*/
public static int generateViewId() {
for (; ; ) {
final int result = sNextGeneratedId.get();
// aapt-generated IDs have the high byte nonzero; clamp to the range under that.
int newValue = result + 1;
if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0.
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) {
// View hierarchy seems to be constructed from the bottom up,
// so all child views are already added. That's why we
// manually call the listener for all children of 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);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
您可以在布局中使用它,就像使用常规一样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>
Run Code Online (Sandbox Code Playgroud)
唉..真怪安卓缺少这么基本的功能。
改编自@ScottBiggs 的回答,这是使用 Kotlin 实现的可能最短的方法:
var currentSelected = button1
listOf<RadioButton>(
button1, button2, button3, ...
).forEach {
it.setOnClickListener { _ ->
currentSelected.isChecked = false
currentSelected = it
currentSelected.isChecked = true
}
}
Run Code Online (Sandbox Code Playgroud)
此解决方案尚未发布,因此发布:
第 0 步:创建一个CompoundButton previousCheckedCompoundButton;
作为全局变量。
第 1 步:创建OnCheckedChangedListener
单选按钮
CompoundButton.OnCheckedChangeListener onRadioButtonCheckedListener = new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (!isChecked) return;
if (previousCheckedCompoundButton != null) {
previousCheckedCompoundButton.setChecked(false);
previousCheckedCompoundButton = buttonView;
} else {
previousCheckedCompoundButton = buttonView;
}
}
};
Run Code Online (Sandbox Code Playgroud)
第 3 步:为所有单选按钮添加侦听器:
radioButton1.setOnCheckedChangeListener(onRadioButtonCheckedListener);
radioButton2.setOnCheckedChangeListener(onRadioButtonCheckedListener);
radioButton3.setOnCheckedChangeListener(onRadioButtonCheckedListener);
radioButton4.setOnCheckedChangeListener(onRadioButtonCheckedListener);
Run Code Online (Sandbox Code Playgroud)
就是这样!!你完成了。
您可以使用这个简单的 RadioGroup 扩展代码。将其中的任何布局/视图/图像与单选按钮一起放入,它将起作用。
它包含选择回调,返回选定的 RadioButton 及其索引,您可以通过索引或 id 以编程方式设置选择:
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import java.util.ArrayList;
public class EnhancedRadioGroup extends RadioGroup implements View.OnClickListener {
public interface OnSelectionChangedListener {
void onSelectionChanged(RadioButton radioButton, int index);
}
private OnSelectionChangedListener selectionChangedListener;
ArrayList<RadioButton> radioButtons = new ArrayList<>();
public EnhancedRadioGroup(Context context) {
super(context);
}
public EnhancedRadioGroup(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (changed) {
getRadioButtons();
}
}
private void getRadioButtons() {
radioButtons.clear();
checkForRadioButtons(this);
}
private void checkForRadioButtons(ViewGroup viewGroup) {
if (viewGroup == null) {
return;
}
for (int i = 0; i < viewGroup.getChildCount(); i++) {
View v = viewGroup.getChildAt(i);
if (v instanceof RadioButton) {
v.setOnClickListener(this);
// store index of item
v.setTag(radioButtons.size());
radioButtons.add((RadioButton) v);
}
else if (v instanceof ViewGroup) {
checkForRadioButtons((ViewGroup)v);
}
}
}
public RadioButton getSelectedItem() {
if (radioButtons.isEmpty()) {
getRadioButtons();
}
for (RadioButton radioButton : radioButtons) {
if (radioButton.isChecked()) {
return radioButton;
}
}
return null;
}
public void setOnSelectionChanged(OnSelectionChangedListener selectionChangedListener) {
this.selectionChangedListener = selectionChangedListener;
}
public void setSelectedById(int id) {
if (radioButtons.isEmpty()) {
getRadioButtons();
}
for (RadioButton radioButton : radioButtons) {
boolean isSelectedRadioButton = radioButton.getId() == id;
radioButton.setChecked(isSelectedRadioButton);
if (isSelectedRadioButton && selectionChangedListener != null) {
selectionChangedListener.onSelectionChanged(radioButton, (int)radioButton.getTag());
}
}
}
public void setSelectedByIndex(int index) {
if (radioButtons.isEmpty()) {
getRadioButtons();
}
if (radioButtons.size() > index) {
setSelectedRadioButton(radioButtons.get(index));
}
}
@Override
public void onClick(View v) {
setSelectedRadioButton((RadioButton) v);
}
private void setSelectedRadioButton(RadioButton rb) {
if (radioButtons.isEmpty()) {
getRadioButtons();
}
for (RadioButton radioButton : radioButtons) {
radioButton.setChecked(rb == radioButton);
}
if (selectionChangedListener != null) {
selectionChangedListener.onSelectionChanged(rb, (int)rb.getTag());
}
}
}
Run Code Online (Sandbox Code Playgroud)
在布局 xml 中使用它:
<path.to.your.package.EnhancedRadioGroup>
Layouts containing RadioButtons/Images/Views and other RadioButtons
</path.to.your.package.EnhancedRadioGroup>
Run Code Online (Sandbox Code Playgroud)
注册回调:
enhancedRadioGroupInstance.setOnSelectionChanged(new EnhancedRadioGroup.OnSelectionChangedListener() {
@Override
public void onSelectionChanged(RadioButton radioButton, int index) {
}
});
Run Code Online (Sandbox Code Playgroud)
没有什么可以阻止您实现该布局结构(RadioGroup
实际上是 的子类LinearLayout
),但您不应该这样做。首先,您创建一个 4 层深的结构(使用另一个布局结构,您可以优化它),其次,如果您RadioButtons
不是 a 的直接子级RadioGroup
,则组中唯一选择的一项将不起作用。这意味着,如果您Radiobutton
从该布局中选择一个,然后选择另一个,RadioButton
您最终会选择两个,RadioButtons
而不是最后选择的一个。
如果您解释一下您想在该布局中做什么,也许我可以推荐您一个替代方案。