sábado, 29 de noviembre de 2014

Pantallas de Preferencias en Android



En el apartado anterior hemos hablado de las Shared Preferences, un mecanismo que nos permite gestionar fácilmente las opciones de una aplicación permitiéndonos guardarlas en XML de una forma transparente para el programador. Y vimos cómo hacer uso de ellas mediante código, es decir, creando nosotros mismos los objetos necesarios (SharedPreferences) y añadiendo, modificando y/o recuperando "a mano" los valores de las opciones a través de los métodos correspondientes (getString(), putString(), …). Sin embargo, ya avisamos de que Android ofrece una forma alternativa de definir mediante XML un conjunto de opciones para una aplicación y crear por nosotros las pantallas necesarias para permitir al usuario modificarlas a su antojo. A esto dedicaremos este segundo apartado sobre preferencias.

Si nos fijamos en cualquier pantalla de preferencias estándar de Android veremos que todas comparten una interfaz común, similar por ejemplo a la que se muestra en las imágenes siguientes para Android 2.x y Android 4.x respectivamente:



Si atendemos por ejemplo a la primera imagen vemos cómo las diferentes opciones se organizan dentro de la pantalla de opciones en varias categorías ("General Settings" y "Slideshow Settings"). Dentro de cada categoría pueden aparecer varias opciones de diversos tipos, como por ejemplo de tipo checkbox ("Confirm deletions") o de tipo lista de selección ("Display size"). He resaltado las palabras "pantalla de opciones", "categorías", y "tipos de opción" porque serán estos los tres elementos principales con los que vamos a definir el conjunto de opciones o preferencias de nuestra aplicación. Empecemos.

Como hemos indicado, nuestra pantalla de opciones la vamos a definir mediante un XML, de forma similar a como definimos cualquier layout, aunque en este caso deberemos colocarlo en la carpeta /res/xml. El contenedor principal de nuestra pantalla de preferencias será el elemento <PreferenceScreen>. Este elemento representará a la pantalla de opciones en sí, dentro de la cual incluiremos el resto de elementos.
Dentro de éste podremos incluir nuestra lista de opciones organizadas por categorías, que se representarán mediante el elemento <PreferenceCategory> al que daremos un texto descriptivo utilizando su atributo android:title. Dentro de cada categoría podremos añadir cualquier número de opciones, las cuales pueden ser de distintos tipos, entre los que destacan:


Cada uno de estos tipos de preferencia requiere la definición de diferentes atributos, que iremos viendo en los siguientes apartados.


CheckBoxPreference

Representa un tipo de opción que sólo puede tomar dos valores distintos: activada o desactivada. Es el equivalente a un control de tipo checkbox. En este caso tan sólo tendremos que especificar los atributos: nombre interno de la opción (android:key), texto a mostrar (android:title) y descripción de la opción (android:summary). Veamos un ejemplo:




EditTextPreference

Representa un tipo de opción que puede contener como valor una cadena de texto. Al pulsar sobre una opción de este tipo se mostrará un cuadro de diálogo sencillo que solicitará al usuario el texto a almacenar. Para este tipo, además de los tres atributos comunes a todas las opciones (key, title y summary) también tendremos que indicar el texto a mostrar en el cuadro de diálogo, mediante el atributo android:dialogTitle. Un ejemplo sería el siguiente:



ListPreference

Representa un tipo de opción que puede tomar como valor un elemento, y sólo uno, seleccionado por el usuario entre una lista de valores predefinida. Al pulsar sobre una opción de este tipo se mostrará la lista de valores posibles y el usuario podrá seleccionar uno de ellos. Y en este caso seguimos añadiendo atributos. 
Además de los cuatro ya comentados (key, title, summary y dialogTitle) tendremos que añadir dos más, uno de ellos indicando la lista de valores a visualizar en la lista y el otro indicando los valores internos que utilizaremos para cada uno de los valores de la lista anterior (Ejemplo: al usuario podemos mostrar una lista con los valores "Español" y "Francés", pero internamente almacenarlos como "ESP" y "FRA").

Estas listas de valores las definiremos también como ficheros XML dentro de la carpeta /res/xml. 
Definiremos para ello los recursos de tipos <string-array> necesarios, en este caso dos, uno para la lista de valores visibles y otro para la lista de valores internos, cada uno de ellos con su ID único correspondiente.
Veamos cómo quedarían dos listas de ejemplo, en un fichero llamado "codigospaises.xml":


En la preferencia utilizaremos los atributos android:entries y android:entryValues para hacer referencia a estas listas, como vemos en el ejemplo siguiente:




MultiSelectListPreference

[A partir de Android 3.0.x / Honeycomb] Las opciones de este tipo son muy similares a las ListPreference, con la diferencia de que el usuario puede seleccionar varias de las opciones de la lista de posibles valores. Los atributos a asignar son por tanto los mismos que para el tipo anterior.


Como ejemplo completo, veamos cómo quedaría definida una pantalla de opciones con las 3 primeras opciones comentadas (ya que probaré con Android 2.2), divididas en 2 categorías llamadas por simplicidad "Categoría 1″ y "Categoría 2″. Llamaremos al fichero "opciones.xml".


Ya tenemos definida la estructura de nuestra pantalla de opciones, pero aún nos queda un paso más para poder hacer uso de ella desde nuestra aplicación. Además de la definición XML de la lista de opciones, debemos implementar una nueva actividad, que será a la que hagamos referencia cuando queramos mostrar nuestra pantalla de opciones y la que se encargará internamente de gestionar todas las opciones guardarlas, modificarlas, etc, a partir de nuestra definición XML.

Android nos facilita las cosas ofreciéndonos una clase de la que podemos derivar fácilmente la nuestra propia y que hace casi todo el trabajo por nosotros. Esta clase se llama PreferenceActivity. Tan sólo deberemos crear una nueva actividad (yo la he llamado OpcionesActivity) que extienda a esta clase, e implementar su evento onCreate() para añadir una llamada al método addPreferencesFromResource(), mediante el que indicaremos el fichero XML en el que hemos definido la pantalla de opciones. Lo vemos mejor directamente en el código:


Así de sencillo, nuestra nueva actividad, al extender a PreferenceActivity, se encargará por nosotros de crear la interfaz gráfica de nuestra lista de opciones según la hemos definido en el XML y se preocupará por nosotros de mostrar, modificar y guardar las opciones cuando sea necesario tras la acción del usuario.

Aunque esto continúa funcionando sin problemas en versiones recientes de Android, la API 11 trajo consigo una nueva forma de definir las pantallas de preferencias haciendo uso de fragments. Para ello, basta simplemente con definir la clase java del fragment, que deberá extender de PreferenceFragment y añadir a su método onCreate() una llamada a addPreferencesFromResource() igual que ya hemos visto antes.


Hecho esto ya no será necesario que la clase de nuestra pantalla de preferencias extienda de PreferenceActivity, sino que podrá ser una actividad normal. Para mostrar el fragment creado como contenido principal de la actividad utilizaríamos el fragment manager para sustituir el contenido de la pantalla (android.R.id.content) por el de nuestro fragment de preferencias recién definido:


Sea cual se la opción elegida para definir la pantalla de preferencias, el siguiente paso será añadir esta actividad al fichero AndroidManifest.xml, al igual que cualquier otra actividad que utilicemos en la aplicación.


Ya sólo nos queda añadir a nuestra aplicación algún mecanismo para mostrar la pantalla de preferencias.
Esta opción suele estar en un menú (para Android 2.x) o en el menú de overflow de la action bar (para Android 3 o superior), pero por simplificar el ejemplo vamos a añadir simplemente un botón (btnPreferencias) que abra la ventana de preferencias.

Al pulsar este botón llamaremos a la ventana de preferencias mediante el método startActivity(), como ya hemos visto en alguna ocasión, al que pasaremos como parámetros el contexto de la aplicación (nos vale con nuestra actividad principal) y la clase de la ventana de preferencias (OpcionesActivity. class).


Y esto es todo, ya sólo nos queda ejecutar la aplicación en el emulador y pulsar el botón de preferencias para mostrar nuestra nueva pantalla de opciones. Debe quedar como muestran las imágenes siguientes (para Android 2 y 4 respectivamente):



La primera opción podemos marcarla o desmarcarla directamente pulsando sobre la check de su derecha.
La segunda, de tipo texto, nos mostrará al pulsarla un pequeño formulario para solicitar el valor de la opción.


Por último, la opción 3 de tipo lista, nos mostrará una ventana emergente con la lista de valores posibles, donde podremos seleccionar sólo uno de ellos.


Una vez establecidos los valores de las preferencias podemos salir de la ventana de opciones simplemente pulsando el botón Atrás del dispositivo o del emulador. Nuestra actividad OpcionesActivity se habrá ocupado por nosotros de guardar correctamente los valores de las opciones haciendo uso de la API de preferencias compartidas (Shared Preferences). Y para comprobarlo vamos a añadir otro botón (btnObtenerOpciones) a la aplicación de ejemplo que recupere el valor actual de las 3 preferencias y los escriba en el log de la aplicación.

La forma de acceder a las preferencias compartidas de la aplicación ya la vimos en el apartado anterior sobre este tema. Obtenemos la lista de preferencias mediante el método getDefaultSharedPreferences() y posteriormente utilizamos los distintos métodos get() para recuperar el valor de cada opción dependiendo de su tipo


Si ejecutamos ahora la aplicación, establecemos las preferencias y pulsamos el nuevo botón de consulta que hemos creado veremos cómo en el log de la aplicación aparecen los valores correctos de cada preferencia. Se mostraría algo como lo siguiente:


Y hasta aquí hemos llegado con el tema de las preferencias, un tema muy interesante de controlar ya que casi ninguna aplicación se libra de hacer uso de ellas.Existen otras muchas opciones de configuración de las pantallas de preferencias, sobre todo con la llegada de Android 4, pero con lo que hemos visto aquí podremos cubrir la gran mayoría de casos.



Saludos compañeros, aprovechen la información.









No hay comentarios:

Publicar un comentario en la entrada