2010-03-04 29 views
28

Como el título lo describe, estoy tratando de agrupar una cuadrícula de botones de radio 3x3 en un solo grupo de radio. En una pregunta anterior, me enteré de que para que los botones de radio correspondan a un solo grupo, tenían que ser los hijos inmediatos del grupo de radio al que corresponderían. Aprendí esto de la peor manera cuando intenté encapsular un diseño de tabla completo (con los botones de opción en las filas de la tabla) en un grupo de radio.¿Cómo agrupar una cuadrícula de 3x3 de botones de radio?

Correr en esa pared, He intentado lo siguiente:

<TableLayout android:id="@+id/table_radButtons" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_below="@+id/title_radGroup_buffer"> 

     <TableRow> 
      <RadioGroup android:layout_width="fill_parent" 
       android:layout_height="wrap_content" 
       android:orientation="horizontal" 
       android:id="@+id/radGroup1"> 

       <RadioButton android:id="@+id/rad1" 
        android:text="Button1" 
        android:layout_width="105px" 
        android:layout_height="wrap_content" 
        android:textSize="13px"></RadioButton> 
       <RadioButton android:id="@+id/rad2" 
        android:text="Button2" 
        android:layout_width="105px" 
        android:textSize="13px" 
        android:layout_height="wrap_content"></RadioButton> 
       <RadioButton android:id="@+id/rad3" 
        android:text="Button3" 
        android:layout_width="105px" 
        android:textSize="13px" 
        android:layout_height="wrap_content"></RadioButton> 
      </RadioGroup> 
     </TableRow> 
     <TableRow> 
      <RadioGroup android:layout_width="fill_parent" 
       android:layout_height="wrap_content" 
       android:orientation="horizontal" 
       android:id="@+id/radGroup1"> 
        <!-- snippet --> 
     </TableRow> 
     <!-- snippet ---> 
</TableLayout> 

Obviamente no aprendí la primera vez porque me encontré con una pared de nuevo. Tenía la esperanza de que los botones de opción en diferentes filas de la tabla se dieran cuenta de que eran parte del mismo grupo de radio (le dieron a cada grupo la misma identificación) pero esto no funcionó.

¿Hay alguna manera de agrupar todos estos botones en un solo grupo de radio y mantener mi estructura 3x3 (3 filas, 3 botones de radio en cada fila)?

Respuesta

54

En realidad no es tan difícil si subclase TableLayout como en este ejemplo

/** 
* 
*/ 
package com.codtech.android.view; 

import android.content.Context; 
import android.util.AttributeSet; 
import android.util.Log; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.RadioButton; 
import android.widget.TableLayout; 
import android.widget.TableRow; 

/** 
* @author diego 
* 
*/ 
public class ToggleButtonGroupTableLayout extends TableLayout implements OnClickListener { 

    private static final String TAG = "ToggleButtonGroupTableLayout"; 
    private RadioButton activeRadioButton; 

    /** 
    * @param context 
    */ 
    public ToggleButtonGroupTableLayout(Context context) { 
     super(context); 
     // TODO Auto-generated constructor stub 
    } 

    /** 
    * @param context 
    * @param attrs 
    */ 
    public ToggleButtonGroupTableLayout(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     // TODO Auto-generated constructor stub 
    } 

    @Override 
    public void onClick(View v) { 
     final RadioButton rb = (RadioButton) v; 
     if (activeRadioButton != null) { 
      activeRadioButton.setChecked(false); 
     } 
     rb.setChecked(true); 
     activeRadioButton = rb; 
    } 

    /* (non-Javadoc) 
    * @see android.widget.TableLayout#addView(android.view.View, int, android.view.ViewGroup.LayoutParams) 
    */ 
    @Override 
    public void addView(View child, int index, 
      android.view.ViewGroup.LayoutParams params) { 
     super.addView(child, index, params); 
     setChildrenOnClickListener((TableRow)child); 
    } 


    /* (non-Javadoc) 
    * @see android.widget.TableLayout#addView(android.view.View, android.view.ViewGroup.LayoutParams) 
    */ 
    @Override 
    public void addView(View child, android.view.ViewGroup.LayoutParams params) { 
     super.addView(child, params); 
     setChildrenOnClickListener((TableRow)child); 
    } 


    private void setChildrenOnClickListener(TableRow tr) { 
     final int c = tr.getChildCount(); 
     for (int i=0; i < c; i++) { 
      final View v = tr.getChildAt(i); 
      if (v instanceof RadioButton) { 
       v.setOnClickListener(this); 
      } 
     } 
    } 

    public int getCheckedRadioButtonId() { 
     if (activeRadioButton != null) { 
      return activeRadioButton.getId(); 
     } 

     return -1; 
    } 
} 

y crear un diseño como éste (por supuesto que necesita para limpiarlo, pero que tuvo la idea)

<?xml version="1.0" encoding="utf-8"?> 
<com.codtech.android.view.ToggleButtonGroupTableLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="wrap_content" android:layout_height="wrap_content" 
    android:id="@+id/radGroup1"> 
    <TableRow> 
      <RadioButton android:id="@+id/rad1" android:text="Button1" 
       android:layout_width="105px" android:layout_height="wrap_content" 
       android:textSize="13px" /> 
      <RadioButton android:id="@+id/rad2" android:text="Button2" 
       android:layout_width="105px" android:textSize="13px" 
       android:layout_height="wrap_content" /> 
      <RadioButton android:id="@+id/rad3" android:text="Button3" 
       android:layout_width="105px" android:textSize="13px" 
       android:layout_height="wrap_content" /> 
    </TableRow> 
    <TableRow> 
      <RadioButton android:id="@+id/rad1" android:text="Button1" 
       android:layout_width="105px" android:layout_height="wrap_content" 
       android:textSize="13px" /> 
      <RadioButton android:id="@+id/rad2" android:text="Button2" 
       android:layout_width="105px" android:textSize="13px" 
       android:layout_height="wrap_content" /> 
      <RadioButton android:id="@+id/rad3" android:text="Button3" 
       android:layout_width="105px" android:textSize="13px" 
       android:layout_height="wrap_content" /> 
    </TableRow> 
    <TableRow> 
      <RadioButton android:id="@+id/rad1" android:text="Button1" 
       android:layout_width="105px" android:layout_height="wrap_content" 
       android:textSize="13px" /> 
      <RadioButton android:id="@+id/rad2" android:text="Button2" 
       android:layout_width="105px" android:textSize="13px" 
       android:layout_height="wrap_content" /> 
      <RadioButton android:id="@+id/rad3" android:text="Button3" 
       android:layout_width="105px" android:textSize="13px" 
       android:layout_height="wrap_content" /> 
    </TableRow> 
</com.codtech.android.view.ToggleButtonGroupTableLayout> 
+1

Tendré que revisar esto y ver si puedo entender exactamente lo que estás haciendo. Gracias. – Fizz

+0

cómo obtener el id del botón marcado cada vez que se cambia? – wolverine

+0

Gracias, esto funcionó a la perfección. Copia, pega, hecho. ¡¡Buena cosa!! – muetzenflo

2

Su única opción es tomar el código fuente a RadioGroup e intentar replicar su funcionalidad en un TableLayout o algo así. De lo contrario, no hay forma de crear una grilla de 3x3 de RadioButtons. Afortunadamente, la clase RadioButton no sabe acerca de RadioGroup - toda la lógica de exclusión mutua está en RadioGroup. Por lo tanto, debería ser posible crear un RadioGrid o algo así ... pero eso va a ser una gran cantidad de trabajo.

+0

¿Así que no hay forma de usar algo como GridView tampoco? – Fizz

+0

Solo si lo subclase y le otorgue las capacidades de RadioGroup. – CommonsWare

2

RadioGroup se extiende de la siguiente manera ..

java.lang.Object 
↳ android.view.View 
    ↳ android.view.ViewGroup 
     ↳ android.widget.LinearLayout 
      ↳ android.widget.RadioGroup 

Si necesita arregle el botón de radio en un diseño de cuadrícula, es posible que deba compilar su propio código personalizado que se extiende desde GridLayout.

0

Es un tumulto pero ¿por qué no? ¿Por qué no? Simplemente use nueve RadioGroups, o tres RadioGroups horizontales, cada uno con tres botones. Cada grupo de radio se puede alinear con un gridView o relativeLayout, etc.

El entonces, en lugar de usar el OnCheckedChangeListener estándar de RadioButton, utiliza el que tiene (del mismo nombre) perteneciente al CompoundButton.

Luego, cuando se presione cualquier RadioButton, puede usar los grupos de radio para anular la selección de los botones de opción. A continuación, seleccione mediante programación el botón de opción en el que se hizo clic.

Es una solución horrible, pero funciona como uno esperaría.

A continuación se muestra un código de ejemplo que solía hacer esto con un diseño de botones 2x2.

public void onActivityCreated(Bundle savedInstanceState) { 
     super.onActivityCreated(savedInstanceState); 

     updateList(Hurricane.ELEVATION_ALL); 

     watermarkAdapter = new WatermarkAdapter(getActivity(), R.layout.watermark_item, 
          relatedHurricanes); 

     setListAdapter(watermarkAdapter); 

     this.getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); 
     this.getView().setBackgroundResource(R.drawable.splash_screen1); 


     getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); 


     View v = this.getView(); 
     filterGroup1 = (RadioGroup)v.findViewById(R.id.filter_rg1); 
     filterGroup2 = (RadioGroup)v.findViewById(R.id.filter_rg2); 
     filterGroup3 = (RadioGroup)v.findViewById(R.id.filter_rg3); 
     filterGroup4 = (RadioGroup)v.findViewById(R.id.filter_rg4); 


     rb1 = (RadioButton) v.findViewById(R.id.first_radio_button);//All 
     rb2 = (RadioButton) v.findViewById(R.id.second_radio_button);//0-6 
     rb4 = (RadioButton) v.findViewById(R.id.third_radio_button);//6-12 
     rb3 = (RadioButton) v.findViewById(R.id.fourth_radio_button);//>=5 

     rb1.setOnCheckedChangeListener(this); 
     rb2.setOnCheckedChangeListener(this); 
     rb3.setOnCheckedChangeListener(this); 
     rb4.setOnCheckedChangeListener(this); 


    } 






@Override 
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 

     filterGroup1.clearCheck(); 
     filterGroup2.clearCheck(); 
     filterGroup3.clearCheck(); 
     filterGroup4.clearCheck(); 


     SharedPreferences prefs = PreferenceManager 
       .getDefaultSharedPreferences(this.getActivity()); 

     int cid = buttonView.getId(); 

     Editor editor  = prefs.edit(); 
     int elevation = Hurricane.ELEVATION_ALL; 
     //All 
     if(rb1.getId() == cid){ 
      elevation = Hurricane.ELEVATION_ALL; 
     } 
     //0-6 
     else if(rb2.getId() == cid){ 
      elevation = Hurricane.ELEVATION_6to12; 
     } 
     //6-12 
     else if(rb3.getId() == cid){  
      elevation = Hurricane.ELEVATION_0to6; 
     } 
     //>=12 
     else if(rb4.getId() == cid){ 
      elevation = Hurricane.ELEVATION_GT12; 
     } 

     update(StormFragment.NORMAL, elevation); 

    } 
5

Después anterior https://stackoverflow.com/a/2383978/5567009 respuesta que obtuve otra solución para esta pregunta, he añadido alguna otra funcionalidad similar, para guardar el estado del grupo y también funcionalidad para borrar la funcionalidad de comprobación como en el grupo de radio.

import android.content.Context; 
import android.os.Parcel; 
import android.os.Parcelable; 
import android.support.annotation.IdRes; 
import android.util.AttributeSet; 
import android.view.View; 
import android.widget.RadioButton; 
import android.widget.TableLayout; 
import android.widget.TableRow; 

public class RadioGridGroup extends TableLayout implements View.OnClickListener { 

    private static final String TAG = "ToggleButtonGroupTableLayout"; 
    private int checkedButtonID = -1; 

    /** 
    * @param context 
    */ 
    public RadioGridGroup(Context context) { 
     super(context); 
     // TODO Auto-generated constructor stub 
    } 

    /** 
    * @param context 
    * @param attrs 
    */ 
    public RadioGridGroup(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     // TODO Auto-generated constructor stub 
    } 

    @Override 
    public void onClick(View v) { 
     if (v instanceof RadioButton) { 
      int id = v.getId(); 
      check(id); 
     } 
    } 

    private void setCheckedStateForView(int viewId, boolean checked) { 
     View checkedView = findViewById(viewId); 
     if (checkedView != null && checkedView instanceof RadioButton) { 
      ((RadioButton) checkedView).setChecked(checked); 
     } 
    } 

    /* (non-Javadoc) 
    * @see android.widget.TableLayout#addView(android.view.View, int, android.view.ViewGroup.LayoutParams) 
    */ 
    @Override 
    public void addView(View child, int index, 
         android.view.ViewGroup.LayoutParams params) { 
     super.addView(child, index, params); 
     setChildrenOnClickListener((TableRow) child); 
    } 


    /* (non-Javadoc) 
    * @see android.widget.TableLayout#addView(android.view.View, android.view.ViewGroup.LayoutParams) 
    */ 
    @Override 
    public void addView(View child, android.view.ViewGroup.LayoutParams params) { 
     super.addView(child, params); 
     setChildrenOnClickListener((TableRow) child); 
    } 


    private void setChildrenOnClickListener(TableRow tr) { 
     final int c = tr.getChildCount(); 
     for (int i = 0; i < c; i++) { 
      final View v = tr.getChildAt(i); 
      if (v instanceof RadioButton) { 
       v.setOnClickListener(this); 
      } 
     } 
    } 


    /** 
    * @return the checked button Id 
    */ 
    public int getCheckedRadioButtonId() { 
     return checkedButtonID; 
    } 


    /** 
    * Check the id 
    * 
    * @param id 
    */ 
    public void check(@IdRes int id) { 
     // don't even bother 
     if (id != -1 && (id == checkedButtonID)) { 
      return; 
     } 
     if (checkedButtonID != -1) { 
      setCheckedStateForView(checkedButtonID, false); 
     } 
     if (id != -1) { 
      setCheckedStateForView(id, true); 
     } 
     setCheckedId(id); 
    } 

    /** 
    * set the checked button Id 
    * 
    * @param id 
    */ 
    private void setCheckedId(int id) { 
     this.checkedButtonID = id; 
    } 

    public void clearCheck() { 
     check(-1); 
    } 

    @Override 
    protected void onRestoreInstanceState(Parcelable state) { 
     if (!(state instanceof SavedState)) { 
      super.onRestoreInstanceState(state); 
      return; 
     } 

     SavedState ss = (SavedState) state; 
     super.onRestoreInstanceState(ss.getSuperState()); 

     this.checkedButtonID = ss.buttonId; 
     setCheckedStateForView(checkedButtonID, true); 
    } 

    @Override 
    protected Parcelable onSaveInstanceState() { 
     Parcelable superState = super.onSaveInstanceState(); 
     SavedState savedState = new SavedState(superState); 
     savedState.buttonId = checkedButtonID; 
     return savedState; 
    } 

    static class SavedState extends BaseSavedState { 
     int buttonId; 

     /** 
     * Constructor used when reading from a parcel. Reads the state of the superclass. 
     * 
     * @param source 
     */ 
     public SavedState(Parcel source) { 
      super(source); 
      buttonId = source.readInt(); 
     } 

     /** 
     * Constructor called by derived classes when creating their SavedState objects 
     * 
     * @param superState The state of the superclass of this view 
     */ 
     public SavedState(Parcelable superState) { 
      super(superState); 
     } 

     @Override 
     public void writeToParcel(Parcel out, int flags) { 
      super.writeToParcel(out, flags); 
      out.writeInt(buttonId); 
     } 

     public static final Parcelable.Creator<SavedState> CREATOR = 
       new Parcelable.Creator<SavedState>() { 
        public SavedState createFromParcel(Parcel in) { 
         return new SavedState(in); 
        } 

        public SavedState[] newArray(int size) { 
         return new SavedState[size]; 
        } 
       }; 
    } 
} 

y utilizar esto en XML de la siguiente manera

<com.test.customviews.RadioGridGroup xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="wrap_contact" 
    android:layout_height="wrap_content"> 

    <TableRow android:layout_marginTop="@dimen/preview_five"> 

     <RadioButton 
      android:id="@+id/rad1" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:text="Button1" /> 

     <RadioButton 
      android:id="@+id/rad2" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:text="Button2" /> 
    </TableRow> 

    <TableRow android:layout_marginTop="@dimen/preview_five"> 

     <RadioButton 
      android:id="@+id/rad3" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:text="Button3" /> 

     <RadioButton 
      android:id="@+id/rad4" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:text="Button4" /> 
    </TableRow> 

    <TableRow android:layout_marginTop="@dimen/preview_five"> 

     <RadioButton 
      android:id="@+id/rad5" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:text="Button5" /> 

     <RadioButton 
      android:id="@+id/rad6" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:text="Button6" /> 
    </TableRow> 

    <TableRow android:layout_marginTop="@dimen/preview_five"> 

     <RadioButton 
      android:id="@+id/rad7" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:text="Button7" /> 

     <RadioButton 
      android:id="@+id/rad8" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:text="Button8" /> 
    </TableRow> 
</com.test.customviews.RadioGridGroup> 

Para cualquier otra mejora, por favor comentar.

+0

en cualquier java paquete puede colocar esto. –

0

I para uno iría para RadioGroups anidados. El Root RadioGroup tendrá una orientación Vertical y sus hijos serán tres RadioGroups con orientación Horizontal.

<RadioGroup 
    android:orientation="vertical"> 
    <RadioGroup 
     android:id="@+id/rg_1" 
     android:orientation="horizontal"> 
     <RadioButton /> 
     <RadioButton /> 
     <RadioButton /> 
    </RadioGroup> 
    <RadioGroup 
     android:id="@id/rg_2" 
     android:orientation="horizontal"> 
     <RadioButton /> 
     <RadioButton /> 
     <RadioButton /> 
    </RadioGroup> 
    <RadioGroup 
     android:id="@+id/rg_3" 
     android:orientation="horizontal"> 
     <RadioButton /> 
     <RadioButton /> 
     <RadioButton /> 
    </RadioGroup> 
</RadioGroup> 

Cada uno de los RadioGroups chield tendrá un ID que será llamado por un objeto RadioGroup dentro del método de validación java. De esta manera:

RadioGroup rg_1 = (RadioGroup) findViewById(R.id.rg_1); 
RadioGroup rg_2 = (RadioGroup) findViewById(R.id.rg_2); 
RadioGroup rg_3 = (RadioGroup) findViewById(R.id.rg_3); 

Ahora simplemente usando clearCheck() dentro de la caja del interruptor puede borrar la verificación de los otros dos RadioGroups. De esta manera:

case R.id.radioButton_1: 
      if (checked) { 
       rg_2.clearCheck(); 
       rg_3.clearCheck(); 
      } 
      break;