jueves, 25 de agosto de 2011

Elementos básicos del interface de usuario – RadioGroup y RadioButton - Basic elements of the user interface

Un RadioButton es un botón con un comportamiento similar al de un interruptor y puede tener dos estados : checked (encendido) o unchecked (apagado).
Normalmente se agrupan varios botones del tipo RadioButton dentro de un RadioGroup y, de este modo, cuando se enciende uno se apagan todos los demás pertenecientes al grupo.
RadioButton también desciende de TextView por lo que hereda todos los atributos que ya conocemos.
La definición en XML de un RadioGroup con varios RadioButton sería algo semejante a esto:

        <RadioGroup
           android:id="@+id/rgrup"
           android:orientation="horizontal"
           android:layout_width="fill_parent"
           android:layout_height="wrap_content"
           >
           <RadioButton
                 android:id="@+id/radio1"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/item1"
             android:checked="false"
                 android:onClick="itemChecked">
           </RadioButton>
           <RadioButton
                 android:id="@+id/radio2"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/item2"
                 android:checked="false"
                 android:onClick="itemChecked">
           </RadioButton>
           <RadioButton
                 android:id="@+id/radio3"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/item3"
                 android:checked="false"
                 android:onClick="itemChecked">
           </RadioButton>
        </RadioGroup>
Como novedades vemos un atributo nuevo android:checked que puede tomar los valores “true” o “false”. Como podeis imaginar sirve para asignar un valor al RadioButton y que aparezca como encendido si tiene el valor true.

Al igual que con Button, podemos aplicar el atributo onClick para definir un método Java a ejecutar en el momento que se pulse sobre el RadioButton.
Podría ser algo así:


public class pruebaRadioButton extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
    public void itemChecked (View v) {

        RadioButton item1 = (RadioButton) findViewById (R.id.radio1);
        RadioButton item2 = (RadioButton) findViewById (R.id.radio2);
        RadioButton item3 = (RadioButton) findViewById (R.id.radio3);
        TextView txtV2 = (TextView) findViewById (R.id.tv2);
    	
    	if (item1.isChecked()) txtV2.setBackgroundColor(Color.RED);
    	if (item2.isChecked()) txtV2.setBackgroundColor(Color.YELLOW);
    	if (item3.isChecked()) txtV2.setBackgroundColor(Color.GREEN);
    }
}

Como veis he definido un pequeño método público llamado itemChecked que recibe como parámetro un objeto  View y en él utilizo el método isChecked para comprobar el estado de cada RadioButton. En el caso de que estén activos cambio el atributo backgroundColor de un TextView definido en la vista. Por supuesto podriamos haber definido un método diferente para cada RadioButton en el XML.
 
Estado inicial

 
item3 checked
 
item2 checked

Hay varias maneras de conseguir este mismo objetivo. Una de ellas es asignar a cada RadioButton un listener desde Java y utilizar el método OnClick() para ejecutar las instrucciones que queramos.
En este caso debemos eliminar el atributo onClick en la definición de cada RadioButton en el archivo XML.
 


public class pruebaRadioButton extends Activity {
    /** Called when the activity is first created. */
	RadioButton item1;
	RadioButton item2;
	RadioButton item3;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        item1 = (RadioButton) findViewById (R.id.radio1);
        item2 = (RadioButton) findViewById (R.id.radio2);
        item3 = (RadioButton) findViewById (R.id.radio3);
        
        // Asigno el listener a cada RadioButton
        item1.setOnClickListener(myListener);
        item2.setOnClickListener(myListener);
        item3.setOnClickListener(myListener);
    }
    // Defino un listener y ejecuto el método itemChecked en onClick
    private OnClickListener myListener = new OnClickListener() {
        public void onClick(View v) {
            // Accion a realizar
            itemChecked();
        }
    };
    private void itemChecked () {

        TextView txtV2 = (TextView) findViewById (R.id.tv2);
    	
    	if (item1.isChecked()) txtV2.setBackgroundColor(Color.RED);
    	if (item2.isChecked()) txtV2.setBackgroundColor(Color.YELLOW);
    	if (item3.isChecked()) txtV2.setBackgroundColor(Color.GREEN);
    }
}


Como veis se define el listener myListener y en su método onClick() llamamos a la función itemChecked que en este caso no recibe ningún parámetro y puede ser privada.
Sólo nos falta asignar el listener a cada RadioGroup con setOnClickListener().


Otra forma de hacer esto mismo es definiendo un objeto Listener (OnCheckedChangeListener) y asignarlo al RadioGroup de manera que podamos controlar cada cambio de estado en cualquier elemento del grupo.

public class pruebaRadioButton extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        RadioGroup rGrup = (RadioGroup) findViewById (R.id.rgrup);
        
        // Defino el listener para el RadioGroup
        OnCheckedChangeListener listenerGrupo = 
            new OnCheckedChangeListener() {
            public void onCheckedChanged(RadioGroup group, int id) {
            	itemChecked (id);
            }
        };
        // Asigno el listener al RadioGroup
        rGrup.setOnCheckedChangeListener(listenerGrupo);
        
    }
    // Como parámetro recibe el id del item que ha cambiado su estado
    private void itemChecked (int id) {

        RadioButton item1 = (RadioButton) findViewById (R.id.radio1);
        RadioButton item2 = (RadioButton) findViewById (R.id.radio2);
        RadioButton item3 = (RadioButton) findViewById (R.id.radio3);
        TextView txtV2 = (TextView) findViewById (R.id.tv2);
    	
        // Compruebo si el id coincide con alguno de los RadioButton
    	if (item1.getId() == id) txtV2.setBackgroundColor(Color.RED);
    	if (item2.getId() == id) txtV2.setBackgroundColor(Color.YELLOW);
    	if (item3.getId() == id) txtV2.setBackgroundColor(Color.GREEN);
    }
}

En este caso también debemos eliminar el atributo onClick del XML puesto que el control de los estados lo haremos con el listener.
El listener recoge el id del elemento que ha variado su estado y se lo mandamos al método itemChecked para investigar de cual se trata y ejecutar el código correspondiente.


Para terminar os comentaré un par de métodos que me han parecido interesantes por su utilidad:
•    clearCheck() : Se utiliza para poner todos los elementos de un RadioGroup en estado de ‘unchecked’.
•    getCheckedRadioButtonId() : Se utiliza para conocer el id del RadioButton que en ese momento tiene estado ‘checked’

Por ejemplo:



RadioGroup rGrup = (RadioGroup) findViewById (R.id.rgrup);
// Leo el ID del RadioButton checked
int idRadio = rGroup.getCheckedRadioButtonId();
// Pongo todos los RadioButtons a unchecked
rGroup.clearCheck(); // 




martes, 16 de agosto de 2011

Elementos básicos del interface de usuario – Buttons - Basic elements of the user interface

Button, al igual que EditText, es una subclase de TextView, y su definición en nuestro Layout se hace incluyendo el siguiente código en el fichero xml :

      <Button 
          android:id="@+id/boton01"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@string/boton01"
          android:onClick="apretaBoton"
          />         

Como en el resto de elementos ya conocidos podemos incluir multitud de atributos que modifcan su apariencia o su situación dentro del Layout que lo contiene, pero voy a hacer especial incapié en el atributo ‘android:onClick’ puesto que es especialmente interesante. El valor de este atributo indica el nombre de la clase Java que se ejecutará cuando el botón sea presionado.  
Para verlo funcionar incluimos este código en nuestro fuente Java:

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
    public void apretaBoton (View view) {
      TextView texto01 = (TextView) findViewById(R.id.texto01);
      texto01.setText("Me han apretado!!");
    }

Como veis he definido una clase pública llamada apretaBoton que recibe como parámetro único un dato tipo View que es la conexión con el elemento del Layout que lo llama.
 

Otra forma de conseguir el mismo resultado es definiendo un objeto ‘onClickListener’ asociado al botón. Este objeto lleva implícita la clase ‘onClick’ en la que definimos lo que debe ejecutarse cuando se aprete el botón :

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        // Capturo el botón a través de su atributo id
        Button boton01 = (Button) findViewById(R.id.boton01);

        // Asocio el objeto onClickLIstener al boton
        boton01.setOnClickListener(new View.OnClickListener() {
             public void onClick(View v) {
                apretaBoton();  // Indico la clase a ejecutar
             }
        });
    }
    // En este caso no recibe ningún parámetro de entrada
    public void apretaBoton () {
      TextView texto01 = (TextView) findViewById(R.id.texto01);
      texto01.setText("Me han apretado!!");
    }

Si utilizamos este método, vemos cómo la clase apretaBoton no necesita ningún parámetro de entrada.
Por cuestiones de claridad, yo prefiero utilizar esta última forma de tratar los botones, aunque podeis utilizar cualquiera.

PERSONALIZANDO NUESTRO BOTONES

Si la apariencia estandard de los botones Android no es de nuestro agrado, podemos modificarla, incluso hacer que varíe su forma según el estado del botón.  Para hacer esto debemos definir un fichero XML en la carpeta res/drawable en el que asociamos la imagen a mostrar según el estado del botón:

Fichero res/drawable/botones.xml
 
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/button_green"
          android:state_pressed="true" />
    <item android:drawable="@drawable/button_red"
          android:state_focused="true" />
    <item android:drawable="@drawable/button_blue" />
</selector> 

Como veis se asocia el estado de pulsado (‘state_pressed’) con la image ‘button_green’


El estado de seleccionado, es decir, cuando recibe el foco, (‘state_focused’) con la imagen ‘button_red’
 


Y el estado normal con la imagen ‘button_blue’
 
Por último incluimos un nuevo atributo a la definición XML del botón indicando : 
 
android:background="@drawable/botones"
 
Con este atributo, normalmente indicamos el archivo drawable que queremos mostrar como botón, sin embargo, al indicar el nombre de un archivo XML podemos personaliazrlo aún más haciendo que cambie según su estado.

Estado ‘Normal’
 


Estado’Focused’ al bajar con las flechas del teclado del simulador
 

Estado ‘Pressed’ al pulsar sobre él
 
La estructura del proyecto ha quedado de la siguiente forma:

La información para esta entrada ha sido obtenida del API de Android en la que podeis profundizar algo más.

Hasta la próxima.