android - seleccionar - ¿Cómo agrupar RadioButton de diferentes LinearLayouts?
radio button android selected (14)
Me preguntaba si es posible agrupar cada RadioButton
en un RadioGroup
único manteniendo la misma estructura. Mi estructura se ve así:
- LinearLayout_main
- LinearLayout_1
- RadioButton1
- LinearLayout_2
- RadioButton2
- LinearLayout_3
- RadioButton3
- LinearLayout_1
Como puede ver, ahora cada RadioButton
es hijo de LinearLayout
diferente. Intenté usar la estructura a continuación, pero no funciona:
- Radiogrupo
- LinearLayout_main
- LinearLayout_1
- RadioButton1
- LinearLayout_2
- RadioButton2
- LinearLayout_3
- RadioButton3
- LinearLayout_1
- LinearLayout_main
Aquí está mi solución basada en la solución @lostdev y la implementación de RadioGroup
. Es un RadioGroup modificado para funcionar con RadioButtons (u otros CompoundButtons) que están anidados dentro de los diseños secundarios.
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);
}
}
}
}
Puedes usarlo en tu diseño de la misma forma que lo RadioGroup
con un RadioGroup
regular, con la excepción de que también funciona con vistas 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>
Bueno, escribí esta clase simple.
Solo úsalo así:
// add any number of RadioButton resource IDs here
GRadioGroup gr = new GRadioGroup(this,
R.id.radioButton1, R.id.radioButton2, R.id.radioButton3);
o
GRadioGroup gr = new GRadioGroup(rb1, rb2, rb3);
// where RadioButton rb1 = (RadioButton) findViewById(R.id.radioButton1);
// etc.
Puede llamarlo en Crear () de Actividad, por ejemplo. No importa en qué RadioButton
haga clic, los demás se desactivarán. Además, no importa, si algunos de los RadioButtons
están dentro de algún RadioGroup
, o no.
Aquí está la clase:
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);
}
}
};
}
Creé estos dos métodos para resolver este problema. Todo lo que tienes que hacer es pasar ViewGroup donde están los RadioButtons (podría ser un RadioGroup, LinearLayout, RelativeLayout, etc.) y establece los eventos OnClick exclusivamente, es decir, siempre que uno de los RadioButtons sea un elemento secundario del ViewGroup ( en cualquier nivel anidado) está seleccionado, los otros están deseleccionados. Funciona con tantos diseños anidados como desee.
public class Utils {
public static void setRadioExclusiveClick(ViewGroup parent) {
final List<RadioButton> radios = getRadioButtons(parent);
for (RadioButton radio: radios) {
radio.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
RadioButton r = (RadioButton) v;
r.setChecked(true);
for (RadioButton r2:radios) {
if (r2.getId() != r.getId()) {
r2.setChecked(false);
}
}
}
});
}
}
private static List<RadioButton> getRadioButtons(ViewGroup parent) {
List<RadioButton> radios = new ArrayList<RadioButton>();
for (int i=0;i < parent.getChildCount(); i++) {
View v = parent.getChildAt(i);
if (v instanceof RadioButton) {
radios.add((RadioButton) v);
} else if (v instanceof ViewGroup) {
List<RadioButton> nestedRadios = getRadioButtons((ViewGroup) v);
radios.addAll(nestedRadios);
}
}
return radios;
}
}
El uso dentro de una actividad sería así:
ViewGroup parent = findViewById(R.id.radios_parent);
Utils.setRadioExclusiveClick(parent);
Escribí mi propia clase de grupo de radio que permite contener botones de opción anidados. Echale un vistazo. Si encuentra errores, hágamelo saber.
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
/**
* This class is used to create a multiple-exclusion scope for a set of compound
* buttons. Checking one compound button that belongs to a group unchecks any
* previously checked compound button within the same group. Intially, all of
* the compound buttons are unchecked. While it is not possible to uncheck a
* particular compound button, the group can be cleared to remove the checked
* state. Basically, this class extends functionality of
* {@link android.widget.RadioGroup} because it doesn''t require that compound
* buttons are direct childs of the group. This means you can wrap compound
* buttons with other views. <br>
* <br>
*
* <b>IMPORTATNT! Follow these instruction when using this class:</b><br>
* 1. Each direct child of this group must contain one compound button or be
* compound button itself.<br>
* 2. Do not set any "on click" or "on checked changed" listeners for the childs
* of this group.
*/
public class CompoundButtonsGroup extends LinearLayout {
private View checkedView;
private OnCheckedChangeListener listener;
private OnHierarchyChangeListener onHierarchyChangeListener;
private OnHierarchyChangeListener onHierarchyChangeListenerInternal = new OnHierarchyChangeListener() {
@Override
public final void onChildViewAdded(View parent, View child) {
notifyHierarchyChanged(null);
if (CompoundButtonsGroup.this.onHierarchyChangeListener != null) {
CompoundButtonsGroup.this.onHierarchyChangeListener.onChildViewAdded(
parent, child);
}
}
@Override
public final void onChildViewRemoved(View parent, View child) {
notifyHierarchyChanged(child);
if (CompoundButtonsGroup.this.onHierarchyChangeListener != null) {
CompoundButtonsGroup.this.onHierarchyChangeListener.onChildViewRemoved(
parent, child);
}
}
};
public CompoundButtonsGroup(Context context) {
super(context);
init();
}
public CompoundButtonsGroup(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CompoundButtonsGroup(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
super.setOnHierarchyChangeListener(this.onHierarchyChangeListenerInternal);
}
@Override
public final void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
this.onHierarchyChangeListener = listener;
}
/**
* Register a callback to be invoked when the checked view changes in this
* group.
*
* @param listener
* the callback to call on checked state change.
*/
public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
this.listener = listener;
}
/**
* Returns currently selected view in this group. Upon empty selection, the
* returned value is null.
*/
public View getCheckedView() {
return this.checkedView;
}
/**
* Returns index of currently selected view in this group. Upon empty
* selection, the returned value is -1.
*/
public int getCheckedViewIndex() {
return (this.checkedView != null) ? indexOfChild(this.checkedView) : -1;
}
/**
* Sets the selection to the view whose index in group is passed in
* parameter.
*
* @param index
* the index of the view to select in this group.
*/
public void check(int index) {
check(getChildAt(index));
}
/**
* Clears the selection. When the selection is cleared, no view in this
* group is selected and {@link #getCheckedView()} returns null.
*/
public void clearCheck() {
if (this.checkedView != null) {
findCompoundButton(this.checkedView).setChecked(false);
this.checkedView = null;
onCheckedChanged();
}
}
private void onCheckedChanged() {
if (this.listener != null) {
this.listener.onCheckedChanged(this.checkedView);
}
}
private void check(View child) {
if (this.checkedView == null || !this.checkedView.equals(child)) {
if (this.checkedView != null) {
findCompoundButton(this.checkedView).setChecked(false);
}
CompoundButton comBtn = findCompoundButton(child);
comBtn.setChecked(true);
this.checkedView = child;
onCheckedChanged();
}
}
private void notifyHierarchyChanged(View removedView) {
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
child.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
check(v);
}
});
CompoundButton comBtn = findCompoundButton(child);
comBtn.setClickable(comBtn.equals(child));
}
if (this.checkedView != null && removedView != null
&& this.checkedView.equals(removedView)) {
clearCheck();
}
}
private CompoundButton findCompoundButton(View view) {
if (view instanceof CompoundButton) {
return (CompoundButton) view;
}
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
CompoundButton compoundBtn = findCompoundButton(((ViewGroup) view)
.getChildAt(i));
if (compoundBtn != null) {
return compoundBtn;
}
}
}
return null;
}
/**
* Interface definition for a callback to be invoked when the checked view
* changed in this group.
*/
public interface OnCheckedChangeListener {
/**
* Called when the checked view has changed.
*
* @param checkedView
* newly checked view or null if selection was cleared in the
* group.
*/
public void onCheckedChanged(View checkedView);
}
}
Esta solución no se ha publicado para publicar:
Paso 0: crear un CompountButton previousCheckedCompoundButton;
como variable global.
Paso 1: Crear OnCheckedChangedListener
para botones de radio
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;
}
}
};
Paso 3: agrega oyente a todos los botones de opción:
radioButton1.setOnCheckedChangeListener(onRadioButtonCheckedListener);
radioButton2.setOnCheckedChangeListener(onRadioButtonCheckedListener);
radioButton3.setOnCheckedChangeListener(onRadioButtonCheckedListener);
radioButton4.setOnCheckedChangeListener(onRadioButtonCheckedListener);
¡¡Eso es!! tu has terminado.
Mi $ 0.02 basado en @infografnet y @lostdev (también gracias @Neromancer por la sugerencia del Botón Compuesto!)
public class AdvRadioGroup {
public interface OnButtonCheckedListener {
void onButtonChecked(CompoundButton button);
}
private final List<CompoundButton> buttons;
private final View.OnClickListener onClick = new View.OnClickListener() {
@Override
public void onClick(View v) {
setChecked((CompoundButton) v);
}
};
private OnButtonCheckedListener listener;
private CompoundButton lastChecked;
public AdvRadioGroup(View view) {
buttons = new ArrayList<>();
parseView(view);
}
private void parseView(final View view) {
if(view instanceof CompoundButton) {
buttons.add((CompoundButton) view);
view.setOnClickListener(onClick);
} else if(view instanceof ViewGroup) {
final ViewGroup group = (ViewGroup) view;
for (int i = 0; i < group.getChildCount();i++) {
parseView(group.getChildAt(i));
}
}
}
public List<CompoundButton> getButtons() { return buttons; }
public CompoundButton getLastChecked() { return lastChecked; }
public void setChecked(int index) { setChecked(buttons.get(index)); }
public void setChecked(CompoundButton button) {
if(button == lastChecked) return;
for (CompoundButton btn : buttons) {
btn.setChecked(false);
}
button.setChecked(true);
lastChecked = button;
if(listener != null) {
listener.onButtonChecked(button);
}
}
public void setOnButtonCheckedListener(OnButtonCheckedListener listener) { this.listener = listener; }
}
Usage (with included listener):
AdvRadioGroup group = new AdvRadioGroup(findViewById(R.id.YOUR_VIEW));
group.setOnButtonCheckedListener(new AdvRadioGroup.OnButtonCheckedListener() {
@Override
public void onButtonChecked(CompoundButton button) {
// do fun stuff here!
}
});
Bonus: You can get the last checked button, the list of entire buttons, and you can check any button by index with this!
No hay nada que te RadioGroup
implementar esa estructura de diseño ( RadioGroup
es de hecho una subclase de LinearLayout
) pero no deberías. En primer lugar, debe crear una estructura de 4 niveles de profundidad (utilizando otra estructura de disposición puede optimizar esto) y, en segundo lugar, si sus RadioButtons
no son RadioGroup
directos de un RadioGroup
, el único elemento seleccionado en el grupo no funcionará. Esto significa que si selecciona un Radiobutton
de ese diseño y luego selecciona otro RadioButton
, terminará con dos RadioButtons
seleccionados en lugar del último seleccionado.
Si explica lo que quiere hacer en ese diseño, tal vez pueda recomendarle una alternativa.
Parece que las buenas personas en Google / Android asumen que cuando usas RadioButtons, no necesitas la flexibilidad que viene con todos los demás aspectos del sistema de interfaz de usuario / diseño de Android. Para decirlo simplemente: no quieren que anides diseños y botones de opción. Suspiro.
Entonces tienes que solucionar el problema. Eso significa que debe implementar botones de radio por su cuenta.
Esto realmente no es muy difícil. En su onCreate (), establezca sus RadioButtons con su propio onClick () para que cuando se activen, configuren Chequeado (verdadero) y hagan lo contrario para los otros botones. Por ejemplo:
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()
}
Sí, lo sé, como en la vieja escuela. Pero funciona. ¡Buena suerte!
Tienes que hacer dos cosas:
- Use
mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
- Haga que su vista de fila personalizada implemente
Checkable
.
Así que creo que la mejor solución es implementar Checkable dentro de tu LinearLayout interno: (gracias a daichan4649, desde su enlace, https://gist.github.com/daichan4649/5245378 , tomé todo el código pegado a continuación)
CheckableLayout.java
package daichan4649.test;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Checkable;
import android.widget.LinearLayout;
public class CheckableLayout extends LinearLayout implements Checkable {
private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked };
public CheckableLayout(Context context) {
super(context, null);
}
public CheckableLayout(Context context, AttributeSet attrs) {
super(context, attrs, 0);
}
public CheckableLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
private boolean checked;
@Override
public boolean isChecked() {
return checked;
}
@Override
public void setChecked(boolean checked) {
if (this.checked != checked) {
this.checked = checked;
refreshDrawableState();
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (child instanceof Checkable) {
((Checkable) child).setChecked(checked);
}
}
}
}
@Override
public void toggle() {
setChecked(!checked);
}
@Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked()) {
mergeDrawableStates(drawableState, CHECKED_STATE_SET);
}
return drawableState;
}
}
inflater_list_column.xml
<?xml version="1.0" encoding="utf-8"?>
<daichan4649.test.CheckableLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/check_area"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical">
<TextView
android:id="@+id/text"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:gravity="center_vertical" />
<RadioButton
android:id="@+id/radio"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false" />
</daichan4649.test.CheckableLayout>
TestFragment.java
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_test, container, false);
// 表示データ
List<String> dataList = new ArrayList<String>();
// 初期選択位置
int initSelectedPosition = 3;
// リスト設定
TestAdapter adapter = new TestAdapter(getActivity(), dataList);
ListView listView = (ListView) view.findViewById(R.id.list);
listView.setAdapter(adapter);
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
listView.setItemChecked(initSelectedPosition, true);
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// 選択状態を要素(checkable)へ反映
Checkable child = (Checkable) parent.getChildAt(position);
child.toggle();
}
});
return view;
}
private static class TestAdapter extends ArrayAdapter<String> {
private LayoutInflater inflater;
public TestAdapter(Context context, List<String> dataList) {
super(context, 0, dataList);
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.inflater_list_column, null);
holder = new ViewHolder();
holder.text = (TextView) convertView.findViewById(R.id.text);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
// bindData
holder.text.setText(getItem(position));
return convertView;
}
}
private static class ViewHolder {
TextView text;
}
Usa esta clase que creé. Encontrará todos los hijos que se puedan verificar en su jerarquía.
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));
}
}
}
I''ve face the same problem as I want to place 4 different radio button in two different linearlayout and these layout will be the child of radio group. To achieve the desire behavior in RadioGroup I have overloaded the addView function
Here is the solution
public class AgentRadioGroup extends RadioGroup
{
public AgentRadioGroup(Context context) {
super(context);
}
public AgentRadioGroup(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void onViewAdded(View child) {
if( child instanceof ViewGroup)
{
ViewGroup viewGroup = (ViewGroup) child;
for(int i=0; i<viewGroup.getChildCount(); i++)
{
View subChild = viewGroup.getChildAt(i);
if( subChild instanceof ViewGroup )
{
onViewAdded(subChild);
}
else
{
if (subChild instanceof RadioButton) {
super.onViewAdded(subChild);
}
}
}
}
if (child instanceof RadioButton)
{
super.onViewAdded(child);
}
}
}
This is a modified version of @Infografnet''s solution. It''s simple and easy to use.
RadioGroupHelper group = new RadioGroupHelper(this,R.id.radioButton1,R.id.radioButton2); group.radioButtons.get(0).performClick(); //programmatically
Just copy and paste
package com.qamar4p.farmer.ui.custom;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.RadioButton;
public class RadioGroupHelper {
public List<CompoundButton> radioButtons = new ArrayList<>();
public RadioGroupHelper(RadioButton... radios) {
super();
for (RadioButton rb : radios) {
add(rb);
}
}
public RadioGroupHelper(Activity activity, int... radiosIDs) {
this(activity.findViewById(android.R.id.content),radiosIDs);
}
public RadioGroupHelper(View rootView, int... radiosIDs) {
super();
for (int radioButtonID : radiosIDs) {
add((RadioButton)rootView.findViewById(radioButtonID));
}
}
private void add(CompoundButton button){
this.radioButtons.add(button);
button.setOnClickListener(onClickListener);
}
View.OnClickListener onClickListener = v -> {
for (CompoundButton rb : radioButtons) {
if(rb != v) rb.setChecked(false);
}
};
}
While this maybe an older topic, i would like to quickly share simple hacky code i wrote.. Its not for everyone and could do with some refinement as well..
The situation to use this code??
This code is for people who have a layout of the original question or similar, in my case it was as below. This personally was for a Dialog that i was using.
- LinLayout_Main
- LinLayout_Row1
- ImageView
- Boton de radio
- LinLayout_Row2
- ImageView
- Boton de radio
- LinLayout_Row3
- ImageView
- Boton de radio
- LinLayout_Row1
What does the code do itself??
This code will enumerate ever Child of "LinLayout_Main" and for each child that is a "LinearLayout" it will then enumerate that View for any RadioButtons.
Simply it will look the parent "LinLayout_Main" and find any RadioButtons that are in any Child LinearLayouts.
MyMethod_ShowDialog
Will show a dialog with a XML layout file while also looking it to set the "setOnClickListener" for each RadioButton it finds
MyMethod_ClickRadio
Will loop each RadioButton the same way "MyMethod_ShowDialog" does but instead of setting the "setOnClickListener" it will instead "setChecked(false)" to clear each RadioButton and then as the last step will "setChecked(false)" to the RadioButton that called the click event.
public void MyMethod_ShowDialog(final double tmpLat, final double tmpLng) {
final Dialog dialog = new Dialog(actMain);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.layout_dialogXML);
final LinearLayout tmpLayMain = (LinearLayout)dialog.findViewById(R.id.LinLayout_Main);
if (tmpLayMain!=null) {
// Perform look for each child of main LinearLayout
int iChildCount1 = tmpLayMain.getChildCount();
for (int iLoop1=0; iLoop1 < iChildCount1; iLoop1++){
View tmpChild1 = tmpLayMain.getChildAt(iLoop1);
if (tmpChild1 instanceof LinearLayout) {
// Perform look for each LinearLayout child of main LinearLayout
int iChildCount2 = ((LinearLayout) tmpChild1).getChildCount();
for (int iLoop2=0; iLoop2 < iChildCount2; iLoop2++){
View tmpChild2 = ((LinearLayout) tmpChild1).getChildAt(iLoop2);
if (tmpChild2 instanceof RadioButton) {
((RadioButton) tmpChild2).setOnClickListener(new RadioButton.OnClickListener() {
public void onClick(View v) {
MyMethod_ClickRadio(v, dialog);
}
});
}
}
}
}
Button dialogButton = (Button)dialog.findViewById(R.id.LinLayout_Save);
dialogButton.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
dialog.dismiss();
}
});
}
dialog.show();
}
public void MyMethod_ClickRadio(View vRadio, final Dialog dDialog) {
final LinearLayout tmpLayMain = (LinearLayout)dDialog.findViewById(R.id.LinLayout_Main);
if (tmpLayMain!=null) {
int iChildCount1 = tmpLayMain.getChildCount();
for (int iLoop1=0; iLoop1 < iChildCount1; iLoop1++){
View tmpChild1 = tmpLayMain.getChildAt(iLoop1);
if (tmpChild1 instanceof LinearLayout) {
int iChildCount2 = ((LinearLayout) tmpChild1).getChildCount();
for (int iLoop2=0; iLoop2 < iChildCount2; iLoop2++){
View tmpChild2 = ((LinearLayout) tmpChild1).getChildAt(iLoop2);
if (tmpChild2 instanceof RadioButton) {
((RadioButton) tmpChild2).setChecked(false);
}
}
}
}
}
((RadioButton) vRadio).setChecked(true);
}
There maybe bugs, copied from project and renamed Voids/XML/ID
You can also run the same type of loop to find out which items are checked
Prueba esta forma de añadir RadioGroup
en LinearLayout
.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<RadioGroup
android:id="@+id/radioGroup1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="1" >
<RadioButton
android:id="@+id/radio0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="RadioButton" />
<RadioButton
android:id="@+id/radio1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RadioButton" />
<RadioButton
android:id="@+id/radio2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RadioButton" />
</RadioGroup>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<RadioGroup
android:id="@+id/radioGroup2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="1" >
<RadioButton
android:id="@+id/radio3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="RadioButton" />
<RadioButton
android:id="@+id/radio4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RadioButton" />
<RadioButton
android:id="@+id/radio5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RadioButton" />
</RadioGroup>
</LinearLayout>
</LinearLayout>