Un RadioButton es uno control de selección que proporciona la interfaz de Android para permitir a los usuarios seleccionar una opción de un conjunto.
Son ideales para elegir uno de varios elementos con exclusión mutua, es decir, la selección de un radio button obliga a descartar la de otro, permitiendo solo a un ítem estar activo.
Si sigues leyendo podrás aprender a:
- Seleccionar un RadioButton
- Obtener valor actual
- Agrupar radio buttons con RadioGroup
- Manejar eventos de estado
- Crear Radio Buttons programáticamente
- Crear Radio buttons desde una base de datos sqlite
- Personalizar la apariencia
Descargar Proyecto En Android Studio
El siguiente video muestra una app que recopila todos los temas que aprenderás en este tutorial:
Si quieres desbloquear el enlace para descargar este proyecto en Android Studio, entonces sigue estas instrucciones:
[sociallocker id=»7121″]
Crear Proyecto En Android Studio
1. Antes de comenzar, abre Android Studio y crea un nuevo proyecto desde File > New > New Project…
Usa los siguientes de configuración:
- Application Name: «RadioButtons»
- Company Domain: «herprogramacion.com»
- Project Location: «D:Proyectos_AndroidRadioButtons»
2. Selecciona API 11: Android 3.0(Honeycomb) como plataforma mínima de ejecución y presiona Next.
3. Cuando te pregunten si deseas añadir una actividad al proyecto, selecciona la plantilla Empty Activity.
4. Te pedirán una configuración básica de la actividad. Para que vayamos a la par usa lo siguientes nombres:
- Activity Name: «ActividadPrincipal»
- Layout Name: «actividad_principal»
Usar RadioButton En Android
Como venía diciendo los radio buttons son excelentes para proporcionar exclusión mutua entre las opciones de un conjunto. Por lo que a diferencia del checkbox, este elemento no cambia de estado al presionarse de nuevo.
Este botón es representado por la clase java RadioButton
al momento de crear un layout.
Su usó es ideal cuando deseas que el usuario vea todas las opciones del conjunto. De lo contrario usa un Spinner para este cometido.
La exclusión la logras con el componente RadioGroup
, el cual agrupa los radio buttons para permitir la selección de uno solamente.
Ejemplo:
Crear un panel de opciones para el sexo en la sección de registro
Solución:
1. Abre actividad_principal.xml y añade una etiqueta nodo <RadioGroup>
, extendida con los valores match_parent
.
Un dato importante. RadioGroup
extiende de LinearLayout
, por lo que es posible usar el atributo android:orientation
para la alineación de los radio buttons. En este caso usaremos la constante horizontal
.
<?xml version="1.0" encoding="utf-8"?> <RadioGroup xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/opciones_sexo" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="horizontal"> </RadioGroup>
2. Añade dos hijos <RadioGroup>
. Uno con la opción «Masculino» y otro con «Femenino».
Usa el atributo android:checked
para determinar el estado de cada radio button.
<?xml version="1.0" encoding="utf-8"?> <RadioGroup xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/opciones_sexo" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="horizontal"> <RadioButton android:id="@+id/radio_masculino" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="16dp" android:checked="true" android:text="Masculino" /> <RadioButton android:id="@+id/radio_femenino" android:layout_width="wrap_content" android:layout_height="wrap_content" android:checked="false" android:text="Femenino" /> </RadioGroup>
Radio Button En Material Design
En la documentación oficial del Material Design especifican que un Radio Button puede atravesar por 5 estados al igual que los otros controles de selección.
- hover: el radio button está a la espera de eventos
- focused: el sistema de navegación de android enfocó al radio button
- pressed: el usuario mantiene presionado el radio button
- disabled: el radio button no está habilitado para interacción
- disabled-focused: combinación de disabled + focused.
Ten en cuenta que el color que usa el radio button al estar activo se deriva del atributo android:colorAccent
que se declara en el tema principal de la app.
Obtener Valor De RadioButton
La obtención del estado de un radio button se realiza con el método isChecked()
de la superclase CompoundButton
. El retorno es booleano, donde true
representa el estado «On» y false
el estado «Off».
RadioButton radioButton = (RadioButton) findViewById(R.id.radio_ejemplo); boolean estado = radioButton.isCheked();
Ejemplo:
Proveer las opciones «Depósito directo» y «Paypal» para el tipo de retiro del afiliado. Disparar un Toast
de alerta si la ubicación del usuario no permite un depósito directo al presionar el botón de guardar.
Solución:
1. Crea un layout cuyo nodo principal sea un RelativeLayout
. Debido a que vas a simular la sección de un formulario usa una etiqueta (TextView
) para la sección con el texto «Opciones de pago».
Por debajo ubica un RadioGroup
con dos RadioButton
para las opciones que se hablaban en la descripción del problema.
Al final adiciona un botón debajo de estas opciones con la acción «GUARDAR».
actividad_principal.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="@dimen/activity_horizontal_margin"> <TextView android:id="@+id/etiqueta_opciones_pago" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/activity_vertical_margin" android:text="Opciones de pago:" android:textAppearance="?android:attr/textAppearanceMedium" /> <RadioGroup android:id="@+id/opciones_pago" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/etiqueta_opciones_pago" android:layout_marginBottom="@dimen/activity_vertical_margin"> <RadioButton android:id="@+id/radio_deposito" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="16dp" android:checked="true" android:text="Depósito directo" /> <RadioButton android:id="@+id/radio_paypal" android:layout_width="wrap_content" android:layout_height="wrap_content" android:checked="false" android:text="Paypal" /> </RadioGroup> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/opciones_pago" android:layout_centerHorizontal="true" android:text="Guardar" /> </RelativeLayout>
2. Para procesar los eventos de click en el botón usa el atributo onClick
en la etiqueta <Button>
. Asigna la firma «comprobarModoPago» de la siguiente forma:
<Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/opciones_pago" android:layout_centerHorizontal="true" android:onClick="comprobarModoPago" android:text="Guardar" />
Y ahora crea el cuerpo en ActividadPrincipal
:
public void comprobarModoPago(View v){ // Acciones }
3. Lo siguiente es comprobar el estado de la opción para el depósito.
Esto requiere comprobar el valor de radio_deposito
con el método isCheck()
al interior de comprobarModoPago()
.
Si está presionado, entonces imprime el mensaje «Comprobar ubicación del usuario».
import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.RadioButton; import android.widget.Toast; public class ActividadPrincipal extends AppCompatActivity { private RadioButton radioDeposito; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.actividad_principal); radioDeposito = (RadioButton) findViewById(R.id.radio_deposito); } public void comprobarModoPago(View v){ if (radioDeposito.isChecked()){ final String text = "Comprobar ubicación del usuario"; Toast.makeText(this, text, Toast.LENGTH_LONG).show(); } } }
Cómo resultado tendrías:
Obtener estado desde el RadioGroup — Desde el grupo puedes obtener el identificador del RadioButton
que tiene el estado On en tiempo de ejecución a través del método getCheckedRadioButtonId()
.
Para el ejemplo anterior puedes obtener primero el RadioGroup
. Luego en el if
de comprobarModoPago()
usa el método del que te hablo para compararlo con R.id.radio_deposito
.
public class ActividadPrincipal extends AppCompatActivity { private RadioGroup grupo; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.actividad_principal); grupo = (RadioGroup) findViewById(R.id.opciones_pago); } public void comprobarModoPago(View view) { if (grupo.getCheckedRadioButtonId() == R.id.radio_deposito) { final String text = "Comprobar ubicación del usuario"; Toast.makeText(this, text, Toast.LENGTH_LONG).show(); } } }
Cambiar Estado
El estado de la clase RadioButton
se hereda de CompoundButton
con el atributo booleano mChecked
, el cual en notación XML se define con android:checked
.
Es intuitivo que el estado On se le atribuye al valor true
y Off a false
(por defecto).
<RadioButton android:id="@+id/radioButton" android:checked="true" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Opción A" />
Si quieres cambiar el estado dinámicamente, entonces usa el método setChecked()
con un parámetro booleano.
Ejemplo:
Marcar el radio button con índice 2 de un grupo de 5 opciones
Solución
1. Modifica el layout de la actividad principal con un nodo LinearLayout
. Su primer hijo será un TextView
con el texto informativo «¿Cuántos días a la semana haces ejercicio?».
La posibilidad de responder al usuario se otorgará con un RadioGroup
de 5 opciones:
- Todos
- Cinco
- Tres
- Uno
- Ninguno
Con la anterior concepción tendrás la siguiente definición XML:
<?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" android:padding="@dimen/activity_vertical_margin"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/activity_vertical_margin" android:text="¿Cuántos días a la semana haces ejercicio?" android:textAppearance="?android:attr/textAppearanceMedium" /> <RadioGroup android:id="@+id/grupo_dias" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_horizontal"> <RadioButton android:id="@+id/opcion_todos" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Todos" /> <RadioButton android:id="@+id/opcion_cinco" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Cinco" /> <RadioButton android:id="@+id/opcion_tres" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Tres" /> <RadioButton android:id="@+id/opcion_uno" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Uno" /> <RadioButton android:id="@+id/opcion_ninguno" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Ninguno" /> </RadioGroup> </LinearLayout>
2. Lo siguiente es obtener el radio button cuyo orden de aparición es 2 (índice basado en 0). Esto puedes hacerlo con getChildAt()
desde el contenedor.
Al obtener la instancia del view, usa el método setChecked()
con el valor de true
para marcarlo.
import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.widget.RadioButton; import android.widget.RadioGroup; public class ActividadPrincipal extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.actividad_principal); RadioGroup contenedor = (RadioGroup) findViewById(R.id.grupo_dias); RadioButton opcionI2 = (RadioButton) contenedor.getChildAt(2); opcionI2.setChecked(true); } }
3. Ejecuta y verás la opción Tres marcada.
Seleccionar RadioButton desde RadioGroup — El ejemplo anterior puede ser modificado para marcar el radiobutton desde el grupo.
Para ello usa el método check()
pasando como parámetro el identificador entero creado en los recursos de android.
Modificación…
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.actividad_principal); RadioGroup contenedor = (RadioGroup) findViewById(R.id.grupo_dias); RadioButton opcionI2 = (RadioButton) contenedor.getChildAt(2); contenedor.check(opcionI2.getId()); }
Recuerda que el método getId()
de la clase View
permite saber el identificador asignado.
Añadir RadioButton En Android Studio
En esta sección te mostraré como ubicar los elementos RadioGroup y RadioButton en el panel de diseño de Android Studio.
Construirás un pequeño grupo de opciones para determinar el estado marital del usuario en una selección única, cuyas opciones son:
- Soltero
- Casado
- Divorciado
- Viudo
Veamos:
1. Abre tu archivo actividad_principal.xml y cambia todo el contenido por un LinearLayout
como padre.
<?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" android:padding="@dimen/activity_horizontal_margin"> </LinearLayout>
2. Cambia de la pestaña Text a Design. Cuando aparezca el lienzo, dirígete a la ventana Palette y arrastra un elemento Plain TextView de la sección Widgets.
Pon en su propiedad text el mensaje «Estado marital:» y cambia su identificador por texto_estado_marital
.
3. Ubícate en la sección Containers de la paleta y arrastra por debajo del texto un elemento RadioGroup
Si das doble click sobre el RadioGroup en el lienzo se abrirá un diálogo emergente para determinar el id del elemento y su orientación. En el primero caso el valor será opciones_estado_marital y en el otro será vertical.
4. El siguiente paso es añadir los 4 RadioButtons para representar las opciones del estado marital.
Ve a la sección Widgets de la paleta y arrastra 4 elementos RadioButton hacia el RadioGroup en el lienzo. Si no logras insertar con precisión el radio, entonces mejor añádelos desde la ventana Component Tree.
Cambia sus ids rápidamente al dar doble click en el lienzo al formato opcion_<valor>
.
Cambia la propiedad text de todos los radios con las opciones que ya habíamos mencionado:
5. Por último determina que el estado Soltero será la opción por defecto al iniciar la app.
Esto puedes hacerlo marcando la propiedad checked de opcion_soltero
.
Otra alternativa para determinar el radio button marcado por defecto es a través de la propiedad checkedButton del componente RadioGroup. Solo especifica el identificador de la opción.
6. Si todo te salió bien, tendrás un código para actividad_principal.xml como el siguiente:
<?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" android:padding="@dimen/activity_horizontal_margin"> <TextView android:id="@+id/texto_estado_marital" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/activity_vertical_margin" android:text="Estado marital:" android:textAppearance="@style/TextAppearance.AppCompat.Body1" /> <RadioGroup android:id="@+id/opciones_estado_marital" android:layout_width="wrap_content" android:layout_height="wrap_content" android:checkedButton="@+id/opcion_soltero" android:orientation="vertical"> <RadioButton android:id="@+id/opcion_soltero" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Soltero" /> <RadioButton android:id="@+id/opcion_casado" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Casado" /> <RadioButton android:id="@+id/opcion_divorciado" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Divorciado" /> <RadioButton android:id="@+id/opcion_viudo" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Viudo" /> </RadioGroup> </LinearLayout>
Manejo De Eventos
Al igual que todos los views, procesa los eventos de click de un RadioButton
con View.OnClickListener
.
Como viste en la sección de botones, puedes asignar con setOnClickListener()
una escucha anónima.
O crear un método con la estructura del controlador onClick()
en la actividad contenedora y luego asignarlo al atributo android:onClick
de cada Radio Button.
Ejemplo
Mostrar los campos Razón social, Representante y Número de empleados si se selecciona Cliente corporativo. De lo contrario, mostrar los campos para nombre completo y profesión para la opción Particular.
Solución:
1. Modifica el archivo actividad_principal.xml
con un LinearLayout
como nodo principal.
El diseño es muy parecido a los anteriores. Tendrás:
- Texto informativo sobre el tipo de cliente
- Conjunto de dos radios.
- Contenedor de formulario con los campos de texto
El RadioButton marcado por defecto será «Particular» por lo que tendremos los campos de texto asociados visibles al inicio. Sin embargo al seleccionar «Corporativo» debes intercambiar la visibilidad de estos elementos con los asociados a este tipo de cliente.
El siguiente diagrama resume la estructura del layout:
La definición en código será:
<?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" android:padding="@dimen/activity_horizontal_margin"> <TextView android:id="@+id/tv_estado_marital" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/activity_vertical_margin" android:text="Tipo de cliente:" android:textAppearance="@style/TextAppearance.AppCompat.Body1" /> <RadioGroup android:id="@+id/rg_tipo_cliente" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="24dp" android:checkedButton="@+id/rb_particular" android:orientation="vertical"> <RadioButton android:id="@+id/rb_corporativo" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Corporativo" /> <RadioButton android:id="@+id/rb_particular" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Particular" /> </RadioGroup> <LinearLayout android:id="@+id/ll_contenedor_particular" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <EditText android:id="@+id/et_nombre" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/activity_vertical_margin" android:hint="Nombre completo" android:inputType="textPersonName" /> <EditText android:id="@+id/et_profesion" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Profesión" /> </LinearLayout> <LinearLayout android:id="@+id/ll_contenedor_corporativo" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:visibility="gone"> <EditText android:id="@+id/et_razon_social" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/activity_vertical_margin" android:hint="Razón social" android:inputType="textPersonName" /> <EditText android:id="@+id/et_representante" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/activity_vertical_margin" android:hint="Representante" android:inputType="textPersonName" /> <EditText android:id="@+id/et_no_empleados" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Número de empleados" android:inputType="number" /> </LinearLayout> </LinearLayout>
El atributo android:visibility
de ll_contenedor_corporativo
será gone
para evitar su aparición en el layout, ya que el cliente particular es la selección por defecto.
2. Añade a los dos RadioButtons en onClick
la firma «onRadioButtonClicked» (o como le quieras llamar al controlador).
Android Studio te permitirá crear el método automáticamente si presionas sobre el texto ALT + ENTER.
El resultado será:
public void onRadioButtonClicked(View view) { // Acciones }
3. Procesa la acción para cada RadioButton según el identificador obtenido desde el parámetro view
. Ten en cuenta que:
- La estructura
switch
es una buena aliada para procesar cada elemento. isChecked()
ve el estado del radio entrante y así mismo determina cada caso.- Debes intercambiar la visibilidad con las constantes
VISIBLE
yGONE
de la claseView
.
Sumando estas características tu código será similar a este:
import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.RadioButton; public class ActividadPrincipal extends AppCompatActivity { private View contenedorParticular; private View contenedorCorporativo; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.actividad_principal); contenedorParticular = findViewById(R.id.ll_contenedor_particular); contenedorCorporativo = findViewById(R.id.ll_contenedor_corporativo); } public void onRadioButtonClicked(View view) { boolean marcado = ((RadioButton) view).isChecked(); switch (view.getId()) { case R.id.rb_corporativo: if (marcado) { mostrarParticular(false); } break; case R.id.rb_particular: if (marcado) { mostrarParticular(true); } break; } } private void mostrarParticular(boolean b) { contenedorParticular.setVisibility(b ? View.VISIBLE : View.GONE); contenedorCorporativo.setVisibility(b ? View.GONE : View.VISIBLE); } }
4. Ejecuta y cambia entre opciones para ver la aparición de cada contenedor:
Como ves, mostrarParticular()
hace visible el formulario del cliente particular si el parámetro b
es true
, de lo contrario en su lugar aparecerá el contenedor del corporativo.
Usar OnCheckedChangeListener en el RadioGroup — Otra opción para configurar una escucha de eventos es a través de la interfaz RadioGroup.OnCheckedChangeListener
.
Esta reacciona ante el cambio de estados de los hijos del contenedor. Simplemente usa el método setOnCheckedChangeListener()
con una nueva instancia anónima en el grupo.
Si implementaras el ejemplo anterior con este nuevo enfoque tendrías la siguiente modificación:
public class ActividadPrincipal extends AppCompatActivity { private View contenedorParticular; private View contenedorCorporativo; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.actividad_principal); contenedorParticular = findViewById(R.id.ll_contenedor_particular); contenedorCorporativo = findViewById(R.id.ll_contenedor_corporativo); RadioGroup opcionesCliente = (RadioGroup)findViewById(R.id.rg_tipo_cliente); opcionesCliente.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup group, int checkedId) { switch (checkedId){ case R.id.rb_particular: mostrarParticular(true); break; case R.id.rb_corporativo: mostrarParticular(false); break; } } }); } private void mostrarParticular(boolean b) { contenedorParticular.setVisibility(b ? View.VISIBLE : View.GONE); contenedorCorporativo.setVisibility(b ? View.GONE : View.VISIBLE); } }
Crear RadioButtons Programáticamente
Usa uno de los constructores de la clase RadioButton
para crear una nueva instancia cuyo contexto sea la actividad.
RadioButton opcion = new RadioButton(this);
Adicionalmente emplea los siguientes métodos para configurar las propiedades de los radios:
Método | Descripción |
---|---|
setLayoutParams() |
Asigna los atributos relacionados al layout, como por ejemplo su ancho y altura |
setId() |
Asigna un identificador descrito en los recursos. Puedes tenerlos en un archivo ids.xml y referirte a ellos como R.id.<nombre> en el parámetro de setId() . |
setText() |
Modifica el texto del radio button |
View.generateViewId() |
Genera un identificador que no colisione con los que ya han sido generados. Aplica para versiones del SDK mayores o igual a 17. |
setOrientation() |
Método de RadioGroup para cambiar la orientación de los radio buttons. Puedes usar la constante View.HORIZONTAL y View.VERTICAL |
setTag() |
Asigna una etiqueta única para un radio buttton. Este método me parece útil cuando se requiere acceder en el futuro a un radio creado dinámicamente. |
addView() |
Añade la nueva instancia del RadioButton al RadioGroup |
Ejemplo
Crear dinámicamente un conjunto de RadioButtons desde un array de strings cuyo contenido son marcas de autos.
Solución:
1. Cambia el contenido de actividad_principal.xml con un nodo LinearLayout
. Declara como primer hijo un TextView
con el texto de presentación y por debajo pon un RadioGroup
vacío.
<?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" android:padding="@dimen/activity_vertical_margin"> <TextView android:id="@+id/tv_marca_auto" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/activity_vertical_margin" android:text="¿Qué marca de auto prefieres?" android:textAppearance="@style/TextAppearance.AppCompat.Title" /> <RadioGroup android:id="@+id/rg_opciones_marca" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
2. Dentro de ActividadPrincipal
crea un método llamado crearRadioButton()
para producir radio buttons, donde la marca de auto sea el parámetro de entrada.
private RadioButton crearRadioButton(String marca) { RadioButton nuevoRadio = new RadioButton(this); LinearLayout.LayoutParams params = new RadioGroup.LayoutParams( RadioGroup.LayoutParams.WRAP_CONTENT, RadioGroup.LayoutParams.WRAP_CONTENT); nuevoRadio.setLayoutParams(params); nuevoRadio.setText(marca); nuevoRadio.setTag(marca); return nuevoRadio; }
Como ves, se crea una nueva instancia de RadioGroup.LayoutParams
para ajustar al contenido del radio con la constante WRAP_CONTENT
. Si deseas expandir la dimensión en todo el padre, usa MATCH_PARENT
.
3. Ahora declara un arreglo de strings con las marcas: «Mazda», «Mercedes Benz», «Audi», «Chevrolet»
La idea es recorrer su contenido con un ciclo for
donde se creará un radio button con crearRadioButton()
y luego se asignará al grupo con addView()
.
Por último cambia el estado del primer radio button a On con el método setCheked()
.
ActividadPrincipal.java
import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.widget.LinearLayout; import android.widget.RadioButton; import android.widget.RadioGroup; public class ActividadPrincipal extends AppCompatActivity { private static String[] MARCAS = { "Mazda", "Mercedes Benz", "Audi", "Chevrolet" }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.actividad_principal); RadioGroup opcionesMarca = (RadioGroup)findViewById(R.id.rg_opciones_marca); for(String marca : MARCAS) { RadioButton nuevoRadio = crearRadioButton(marca); opcionesMarca.addView(nuevoRadio); } RadioButton primerRadio = (RadioButton) opcionesMarca.getChildAt(0); primerRadio.setChecked(true); } private RadioButton crearRadioButton(String marca) { RadioButton nuevoRadio = new RadioButton(this); LinearLayout.LayoutParams params = new RadioGroup.LayoutParams( RadioGroup.LayoutParams.WRAP_CONTENT, RadioGroup.LayoutParams.WRAP_CONTENT); nuevoRadio.setLayoutParams(params); nuevoRadio.setText(marca); nuevoRadio.setTag(marca); return nuevoRadio; } }
4. La ejecución mostrará el resultado final:
Crear RadioButtons Desde SQLite
Existen casos donde tendrás una serie de datos en una base de datos SQLite que representan cada una de las opciones que irán en un RadioGroup.
En ese caso debes consultar los datos de la tabla específica y luego recorrer el cursor resultante para obtener el texto del RadioButton.
Ejemplo
Obtener las opciones de respuesta para la pregunta «¿A qué animal nunca dejan de crecerle los dientes?» desde la base de datos
Solución
1. Lo primero es definir el layout del requerimiento.
Al igual que los casos anteriores, tendremos un TextView
para informar al usuario de la selección que se encuentra por debajo en un RadioGroup
.
actividad_principal.xml
<?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" android:padding="@dimen/activity_vertical_margin"> <TextView android:id="@+id/tv_pregunta" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/activity_vertical_margin" android:text="¿A qué animal nunca dejan de crecerle los dientes?" android:textAppearance="@style/TextAppearance.AppCompat.Title" /> <RadioGroup android:id="@+id/rg_respuestas" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
2. La creación de la base de datos local arranca con una clase de contrato que disponga de todos los nombres y cualidades que tendrán las tablas.
Ve al menú de herramientas y presiona File > New > Java Class y crea una clase con el nombre Contrato
.
Debido a que tenemos solo una tabla llamada respuesta cuyos campos son el identificador y el texto de la respuesta, el contenido del contrato se resume a:
/** * Convenciones de nombrado en la base de datos SQLite local */ public class Contrato { interface ColumnasRespuesta { String RESPUESTA = "respuesta"; } private Contrato() { } }
Básicamente el modelo se podría ilustrar así:
Aunque es un ejemplo básico, te será de ayuda para experimentar la dinámica.
Si quieres aprender diseños de bases de datos, entonces descarga mi ebook con una serie de pasos para facilitarte esta tarea.
3. Ahora crea el controlador de la base de datos para describir como se creará la estructura inicial.
Recuerda que solo debes crear una nueva clase java que extienda de SQLiteOpenHelper
y luego sobrescribir los controladores onCreate()
y onUpgrade()
.
En la creación usa el comando CREATE TABLE
para crear la tabla respuesta y añade 4 registros con los siguientes strings.
- A. Castor
- B. Jaguar
- C. Elefante
- D. Rinoceronte
En la actualización elimina la tabla respuesta y vuelve a crearla.
También es necesario crear un método get para conseguir todos los registros de las respuestas. Llámalo getRespuestas()
y realiza el query necesario.
Al final tu controlador tendría un código similar al siguiente:
ControladorSQLite.java
import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.provider.BaseColumns; /** * Controlador de operaciones de la base de datos */ public class ControladorSQLite extends SQLiteOpenHelper { private static final String NOMBRE_BASE_DATOS = "preguntas.db"; private static final int VERSION_ACTUAL = 1; private final Context contexto; interface Tablas { String RESPUESTA = "respuesta"; } public ControladorSQLite(Context contexto) { super(contexto, NOMBRE_BASE_DATOS, null, VERSION_ACTUAL); this.contexto = contexto; } @Override public void onCreate(SQLiteDatabase db) { String respuesta = Contrato.ColumnasRespuesta.RESPUESTA; String scriptCreate = "CREATE TABLE " + Tablas.RESPUESTA + "(" + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + respuesta + " TEXT UNIQUE NOT NULL)"; db.execSQL(scriptCreate); ContentValues cv = new ContentValues(); cv.put(respuesta, "A. Castor"); db.insert(Tablas.RESPUESTA, BaseColumns._ID, cv); cv.put(respuesta, "B. Jaguar"); db.insert(Tablas.RESPUESTA, BaseColumns._ID, cv); cv.put(respuesta, "C. Elefante"); db.insert(Tablas.RESPUESTA, BaseColumns._ID, cv); cv.put(respuesta, "D. Rinoceronte"); db.insert(Tablas.RESPUESTA, BaseColumns._ID, cv); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS " + Tablas.RESPUESTA); onCreate(db); } public Cursor getRespuestas() { SQLiteDatabase db = getReadableDatabase(); return db.query(Tablas.RESPUESTA, null, null, null, null, null, null); } }
4. Finalmente ve a la actividad principal y crea una instancia en del controlador sqlite en onCreate()
.
La idea es crear los radios programáticamente como viste en la sección anterior.
Usa un ciclo while
para recorrer el cursor que retorna el método getRespuestas()
. En cada iteración obtén la columna "respuesta"
con el método getString()
y usa su contenido para crear el RadioButton
.
import android.database.Cursor; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.widget.LinearLayout; import android.widget.RadioButton; import android.widget.RadioGroup; public class ActividadPrincipal extends AppCompatActivity { private ControladorSQLite sqLiteOpenHelper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.actividad_principal); RadioGroup opcionesMarca = (RadioGroup) findViewById(R.id.rg_respuestas); sqLiteOpenHelper = new ControladorSQLite(this); Cursor c = sqLiteOpenHelper.getRespuestas(); while (c.moveToNext()) { String respuesta = c.getString(c.getColumnIndex(Contrato.ColumnasRespuesta.RESPUESTA)); opcionesMarca.addView(crearRadioButton(respuesta)); } } private RadioButton crearRadioButton(String respuesta) { RadioButton nuevoRadio = new RadioButton(this); LinearLayout.LayoutParams params = new RadioGroup.LayoutParams( RadioGroup.LayoutParams.WRAP_CONTENT, RadioGroup.LayoutParams.WRAP_CONTENT); nuevoRadio.setLayoutParams(params); nuevoRadio.setText(respuesta); nuevoRadio.setTag(respuesta); return nuevoRadio; } }
Importante que uses servicios o tareas asíncronas para consultar la base de datos y no atrofiar el hilo principal de la app.
5. Ejecuta el proyecto y tendrás los radio buttons en su lugar:
Cambiar Color Del Botón
Una de las formas de personalizar un RadioButton es cambiar el color de su botón.
Esta sección te mostrará dos formas para hacerlo:
1. Usar el atributo app:buttonTint
sobre el RadioButton
. Sin embargo, debido a que cambia el drawable completo, verás que el estado Off también cambia su tinte.
<RadioButton android:id="@+id/radioButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="3 o más" app:buttonTint="@color/colorPrimary" />
2. La otra alternativa es aprovechar el atributo android:colorAccent
. Recuerda que por defecto este será el color del estado activo del RadioButton
, así que puedes usar el atributo android:theme
para sobrescribir dicho elemento y personalizar únicamente el view.
styles.xml
<style name="RadioButtonLima"> <item name="colorAccent">#D4E157</item> </style>
layout
<RadioButton android:id="@+id/radioButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Entre 10 y 15" android:theme="@style/RadioButtonLima" />
Cambiar Imagen Del Background
Si necesitas cambiar el background completo del RadioButton, necesitas crear un drawable con una lista de estados (<selector>
).
Para hacerlo debes crear como mínimo dos backgrounds. Uno para el estado On y otro para Off. Podrías también implementar el estado deshabilitado y enfocado si llegas a requerirlos en la vida de tu UI.
La idea es que uses los atributos android:background
y android:button
para cambiar el background completo del componente o solo el del botón.
Ejemplo
Crear un background personalizado para un conjunto de 4 RadioButtons que representan una selección del clima.
Solución:
1. Como ves en la ilustración anterior, este conjunto de radio buttons tiene un estilo parecido al componente Button Group del framework Bootstrap.
Te voy a mostrar cómo hacer el primer botón de lluvia para que te guíes. Los demás siguen el mismo patrón.
Lo primero es producir el drawable que represente la imagen del botón, en este caso son iconos relacionados al clima. Algunos métodos para hacerlo son:
- Crear imágenes png en diferentes tamaños para el soporte de cambio de dimensiones,
- Usar nine patchs para extender una estructura simple sobre un rectángulo,
- Crear figuras elementales en definiciones XML (
<shape>
), - Usar vectores
- etc.
En mi caso usaré vectores.
Para ello ve a Material Design Icons y busca el icono que satisfaga tu necesidad. En mi caso fué weather-rainy de Austin Andrews. Luego selecciona View Vector Drawable.
Esto arrojará el código XML para el nuevo drawable que crearemos en Android Studio.
Presiona Download .xml para descargar el archivo o copia el código directamente.
Esto debe producirte un archivo dentro de res/drawable al que llamarás ic_clima_lluvia.xml con el siguiente contenido.
<?xml version="1.0" encoding="utf-8"?> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportHeight="24" android:viewportWidth="24"> <path android:fillColor="#fff" android:pathData="M6,14A1,1 0 0,1 7,15A1,1 0 0,1 6,16A5,5 0 0,1 1,11A5,5 0 0,1 6,6C7,3.65 9.3,2 12,2C15.43,2 18.24,4.66 18.5,8.03L19,8A4,4 0 0,1 23,12A4,4 0 0,1 19,16H18A1,1 0 0,1 17,15A1,1 0 0,1 18,14H19A2,2 0 0,0 21,12A2,2 0 0,0 19,10H17V9A5,5 0 0,0 12,4C9.5,4 7.45,5.82 7.06,8.19C6.73,8.07 6.37,8 6,8A3,3 0 0,0 3,11A3,3 0 0,0 6,14M14.83,15.67C16.39,17.23 16.39,19.5 14.83,21.08C14.05,21.86 13,22 12,22C11,22 9.95,21.86 9.17,21.08C7.61,19.5 7.61,17.23 9.17,15.67L12,11L14.83,15.67M13.41,16.69L12,14.25L10.59,16.69C9.8,17.5 9.8,18.7 10.59,19.5C11,19.93 11.5,20 12,20C12.5,20 13,19.93 13.41,19.5C14.2,18.7 14.2,17.5 13.41,16.69Z" /> </vector>
2. Necesitas que este elemento tenga por debajo un background sólido con un color que dependa del estado.
Así que define los colores On y Off en colors.xml de la siguiente forma:
<color name="colorRadioButtonOn">#2980b9</color> <color name="colorRadioButtonOff">#3498db</color>
Ambos tonos son la variación de un azul tipo Flat Design.
3. Crea un drawable por capas (<layer-list>
) para el estado On donde se ponga por debajo un rectángulo con fondo colorRadioButtonOn
y añade arco a sus bordes izquierdo.
Por encima irá el icono con 10dp
de padding en toda dirección:
rb_background_lluvia_on.xml
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item> <shape android:shape="rectangle"> <corners android:bottomLeftRadius="10dp" android:topLeftRadius="10dp" /> <solid android:color="@color/colorRadioButtonOn" /> </shape> </item> <item android:bottom="10dp" android:drawable="@drawable/ic_clima_lluvia" android:left="10dp" android:right="10dp" android:top="10dp" /> </layer-list>
El estado Off es idéntico, solo que usas a colorRadioButtonOff
en el rectángulo.
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item> <shape android:shape="rectangle"> <corners android:bottomLeftRadius="10dp" android:topLeftRadius="10dp" /> <solid android:color="@color/colorRadioButtonOff" /> </shape> </item> <item android:bottom="10dp" android:drawable="@drawable/ic_clima_lluvia" android:left="10dp" android:right="10dp" android:top="10dp" /> </layer-list>
4. Crea el drawable que representará el background final del RadioButton. Solo debes añadir un selector con dos ítems.
El primero representará el estado marcado (state_checked = "true"
) y el segundo el estado Off (state_checked="false"
).
rb_background_lluvia.xml
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/rb_background_lluvia_on" android:state_checked="true" /> <item android:drawable="@drawable/rb_background_lluvia_off" android:state_checked="false" /> </selector>
5. Modifica el layout de la actividad principal y añade un RadioGroup con 4 opciones.
Cada uno de ellos no debe tener texto y su atributo android:background
debe tener asignado @null
.
Solo usarás android:button
al cuál asignarás el background que acabas de construir.
actividad_principal.xml
<?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:gravity="center" android:orientation="vertical"> <RadioGroup android:layout_width="wrap_content" android:layout_height="wrap_content" android:checkedButton="@+id/rb_lluvia" android:orientation="horizontal"> <RadioButton android:id="@+id/rb_lluvia" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@null" android:button="@drawable/rb_background_lluvia" /> <RadioButton android:id="@+id/rb_nublado" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@null" android:button="@drawable/rb_background_nublado" /> <RadioButton android:id="@+id/rb_soleado" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@null" android:button="@drawable/rb_background_soleado" /> <RadioButton android:id="@+id/rb_torrencial" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@null" android:button="@drawable/rb_background_torrencial" /> </RadioGroup> </LinearLayout>
Conclusión
¿Cómo te fue con el control RadioButton
?
De seguro encontraste varias características que te ayudaran en la UI de tu app.
Recuerda que este widget es ideal cuando es necesario la selección de una sola opción entre un conjunto.
Te será de gran ayuda en formularios al combinarlo con checkboxes, campos de texto, raised buttons, etc.
Incluso reflejar datos de sqlite, determinar acciones en diálogos o crear preferencias para el usuario.