Comment grouper RadioButton à partir de LinearLayouts différents?

Je me demandais s’il est possible de regrouper chaque RadioButton dans un RadioGroup unique en conservant la même structure. Ma structure ressemble à ceci:

  • LinearLayout_main
    • LinearLayout_1
      • RadioButton1
    • LinearLayout_2
      • RadioButton2
    • LinearLayout_3
      • RadioButton3

Comme vous pouvez le voir, chaque RadioButton est maintenant un enfant de LinearLayout différent. J’ai essayé d’utiliser la structure ci-dessous, mais cela ne fonctionne pas:

  • Radiogroupe
    • LinearLayout_main
      • LinearLayout_1
        • RadioButton1
      • LinearLayout_2
        • RadioButton2
      • LinearLayout_3
        • RadioButton3

Il semble que les bonnes personnes de Google / Android supposent que lorsque vous utilisez RadioButtons, vous n’avez pas besoin de la flexibilité associée à tous les autres aspects de l’interface utilisateur / système de présentation Android. Pour le dire simplement: ils ne veulent pas que vous imbriciez des dispositions et des boutons radio. Soupir.

Donc, vous devez contourner le problème. Cela signifie que vous devez implémenter les boutons radio par vous-même.

Ce n’est vraiment pas trop difficile. Dans votre onCreate (), configurez vos RadioButtons avec leur propre onClick () de sorte que lorsqu’ils sont activés, ils définissent Checked (true) et font le contraire pour les autres boutons. Par exemple:

 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() } 

Oui, je connais la vieille école. Mais ça marche. Bonne chance!

Utilisez cette classe que j’ai créée. Il trouvera tous les enfants vérifiables dans votre hiérarchie.

 import java.util.ArrayList; import android.content.Context; import android.util.AtsortingbuteSet; import android.view.View; import android.view.ViewGroup; import android.widget.Checkable; import android.widget.LinearLayout; public class MyRadioGroup extends LinearLayout { private ArrayList mCheckables = new ArrayList(); public MyRadioGroup(Context context) { super(context); } public MyRadioGroup(Context context, AtsortingbuteSet attrs) { this(context, attrs, 0); } public MyRadioGroup(Context context, AtsortingbuteSet 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)); } } } 

Eh bien, j’ai écrit cette classe simple.

Utilisez-le simplement comme ceci:

 // add any number of RadioButton resource IDs here GRadioGroup gr = new GRadioGroup(this, R.id.radioButton1, R.id.radioButton2, R.id.radioButton3); 

ou

 GRadioGroup gr = new GRadioGroup(rb1, rb2, rb3); // where RadioButton rb1 = (RadioButton) findViewById(R.id.radioButton1); // etc. 

Vous pouvez l’appeler par exemple dans onCreate (). Quel que soit le RadioButton sur lequel vous cliquez, les autres seront décochés. En outre, peu importe si certains RadioGroup sont à l’intérieur d’un groupe de RadioGroup , ou pas.

Voici le cours:

 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 radios = new ArrayList(); /** * 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); } } }; } 

Voici ma solution basée sur la solution @lostdev et l’implémentation de RadioGroup . C’est un RadioGroup modifié pour fonctionner avec RadioButtons (ou d’autres CompoundButtons) qui sont nesteds dans des mises en page enfant.

 import android.content.Context; import android.os.Build; import android.support.annotation.IdRes; import android.support.annotation.Nullable; import android.util.AtsortingbuteSet; 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)); } } /** * 

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()}.

* * @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); } } /** *

Returns the identifier of the selected radio button in this group. * Upon empty selection, the returned value is -1.

* * @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; } /** *

Clears the selection. When the selection is cleared, no radio button * in this group is selected and {@link #getCheckedItemId()} returns * null.

* * @see #check(CompoundButton) * @see #getCheckedItemId() */ public void clearCheck() { check(null); } /** *

Register a callback to be invoked when the checked radio button * changes in this group.

* * @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); } } } }

Vous pouvez l'utiliser dans votre mise en page de la même manière que vous le feriez avec un RadioGroup à l'exception du fait qu'il fonctionne également avec les vues RadioButton nestedes:

            

J’ai créé ces deux méthodes pour résoudre ce problème. Tout ce que vous avez à faire est de passer le ViewGroup où se trouvent les RadioButtons (pourrait être un RadioGroup, LinearLayout, RelativeLayout, etc.) et il définit uniquement les événements OnClick, c’est-à-dire chaque fois qu’un des RadioButtons est un enfant du ViewGroup ( à n’importe quel niveau nested) est sélectionné, les autres sont désélectionnés. Il fonctionne avec autant de dispositions nestedes que vous le souhaitez.

 public class Utils { public static void setRadioExclusiveClick(ViewGroup parent) { final List 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 getRadioButtons(ViewGroup parent) { List radios = new ArrayList(); 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 nestedRadios = getRadioButtons((ViewGroup) v); radios.addAll(nestedRadios); } } return radios; } } 

L’utilisation dans une activité serait comme ceci:

 ViewGroup parent = findViewById(R.id.radios_parent); Utils.setRadioExclusiveClick(parent); 

J’ai écrit ma propre classe de groupe radio qui permet de contenir des boutons radio nesteds. Vérifiez-le. Si vous trouvez des bugs, faites-le moi savoir.

 import android.content.Context; import android.util.AtsortingbuteSet; 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. 
*
* * IMPORTATNT! Follow these instruction when using this class:
* 1. Each direct child of this group must contain one compound button or be * compound button itself.
* 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, AtsortingbuteSet attrs) { super(context, attrs); init(); } public CompoundButtonsGroup(Context context, AtsortingbuteSet 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); } }

Vous devez faire deux choses:

  1. Utilisez mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
  2. Rendez votre vue de ligne personnalisée implémentable.

Donc, je pense que la meilleure solution est d’implémenter Checkable dans votre LinearLayout interne: (grâce à daichan4649, depuis son lien https://gist.github.com/daichan4649/5245378 , j’ai pris tout le code collé ci-dessous)

VérifiableLayout.java

 package daichan4649.test; import android.content.Context; import android.util.AtsortingbuteSet; 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, AtsortingbuteSet attrs) { super(context, attrs, 0); } public CheckableLayout(Context context, AtsortingbuteSet 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

      

TestFragment.java

 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_test, container, false); // 表示データList dataList = new ArrayList(); // 初期選択位置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 { private LayoutInflater inflater; public TestAdapter(Context context, List 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; } 

Il n’y a rien qui vous empêche d’implémenter cette structure ( RadioGroup est en fait une sous-classe de LinearLayout ) mais vous ne devriez pas. Tout d’abord, vous créez une structure de 4 niveaux de profondeur (en utilisant une autre structure de mise en forme que vous pourriez optimiser) et deuxièmement, si vos RadioGroup ne sont pas des enfants directs d’un RadioGroup , le seul élément sélectionné dans le groupe ne fonctionnera pas. Cela signifie que si vous sélectionnez un Radiobutton partir de cette mise en page, puis sélectionnez un autre RadioButton vous obtiendrez deux RadioButtons au lieu du dernier sélectionné.

Si vous expliquez ce que vous voulez faire dans cette mise en page, je peux vous recommander une alternative.

Cette solution n’a pas encore été publiée:

Étape 0: créez un CompountButton previousCheckedCompoundButton; comme variable globale.

Étape 1: Créer OnCheckedChangedListener pour les boutons 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; } } }; 

Étape 3: ajoutez un écouteur à tous les boutons radio:

 radioButton1.setOnCheckedChangeListener(onRadioButtonCheckedListener); radioButton2.setOnCheckedChangeListener(onRadioButtonCheckedListener); radioButton3.setOnCheckedChangeListener(onRadioButtonCheckedListener); radioButton4.setOnCheckedChangeListener(onRadioButtonCheckedListener); 

C’est tout!! vous avez terminé.

Mon 0,02 $ basé sur @infografnet et @lostdev (merci aussi @Neromancer pour la suggestion du bouton composé!)

 public class AdvRadioGroup { public interface OnButtonCheckedListener { void onButtonChecked(CompoundButton button); } private final List 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 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; } } 

Utilisation (avec auditeur inclus):

 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: vous pouvez obtenir le dernier bouton coché, la liste des boutons entiers, et vous pouvez vérifier n’importe quel bouton par index avec ceci!

Bien que ce sujet soit peut-être un sujet plus ancien, je voudrais rapidement partager un code de piratage simple que j’ai écrit. Ce n’est pas pour tout le monde et pourrait également être amélioré.

La situation pour utiliser ce code ??
Ce code est destiné aux personnes qui ont une mise en page de la question d’origine ou similaire, dans mon cas, c’était comme ci-dessous. C’était personnellement pour un dialog que j’utilisais.

  • LinLayout_Main
    • LinLayout_Row1
      • ImageView
      • Bouton radio
    • LinLayout_Row2
      • ImageView
      • Bouton radio
    • LinLayout_Row3
      • ImageView
      • Bouton radio

Que fait le code lui-même?
Ce code énumérera toujours Child de “LinLayout_Main” et pour chaque enfant qui est un “LinearLayout”, il énumérera alors cette vue pour tous les boutons radio.

Il suffit de regarder le parent “LinLayout_Main” et de trouver tous les boutons radio qui se trouvent dans les lignes LinearLayout.

MyMethod_ShowDialog
Affiche un dialog avec un fichier de mise en page XML tout en le regardant pour définir “setOnClickListener” pour chaque RadioButton trouvé

MyMethod_ClickRadio
Bouillera chaque RadioButton de la même manière que “MyMethod_ShowDialog” mais au lieu de définir “setOnClickListener”, il va plutôt “setChecked (false)” pour effacer chaque RadioButton et ensuite la dernière étape “setChecked (false)” pour RadioButton l’événement click.

 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

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

Voici la solution

 public class AgentRadioGroup extends RadioGroup { public AgentRadioGroup(Context context) { super(context); } public AgentRadioGroup(Context context, AtsortingbuteSet attrs) { super(context, attrs); } @Override public void onViewAdded(View child) { if( child instanceof ViewGroup) { ViewGroup viewGroup = (ViewGroup) child; for(int i=0; i 

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 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); } }; } 

Sigh.. Really blame that Android lacks such a basic functionality.

Adapted from @ScottBiggs answer, here’s the possibly shortest way to do it with Kotlin:

 var currentSelected = button1 listOf( button1, button2, button3, ... ).forEach { it.setOnClickListener { _ -> currentSelected.isChecked = false currentSelected = it currentSelected.isChecked = true } } 

Try this way to add RadioGroup in LinearLayout .