Como cada domingo, llega un nuevo capítulo en Aprende Android en 20 conceptos. Hasta ahora, hemos visto los fundamentos y recursos de una aplicación, y las actividades y los fragmentos, con lo que hemos visto algunos de los conceptos más importantes. Pero esto no significa que no quede mucho por ver aún. Hoy veremos cómo crear nuestra propio objeto View personalizado y cómo utilizar los adaptadores, tan útiles en listas o galerías, por ejemplo.
5. View personalizada
Como programadores, la plataforma Android está constituida en un modelo basado en unos componentes muy potentes y sofisticados, de forma que podremos prácticamente crear cualquier interfaz gráfica posible. Para ello, nos basaremos en las clases fundamentales de los layouts: las clases View y ViewGroup. La clase View representa el bloque básico para cuando queremos crear una interfaz gráfica. Por su parte, un ViewGroup no es más que una View específica que nos permite contener otras Views. Estas dos clases serán los componentes centrales de cualquier interfaz Android.
La API de Android nos ofrece de serie una variedad de Views (en la API llamadas widgets) y ViewGroups (layouts) sobre los que podemos empezar a trabajar. Estos son algunos de los ejemplos que podemos encontrar:
- Views: Button, TextView, EditText, ListView, CheckBox, RadioButton, Gallery, Spinner, AutoCompleteTextView, ImageSwitcher, TextSwitcher…
- ViewGroups: LinearLayout, FrameLayout, RelativeLayout…
Puesto que los layouts son algo de lo más importante para nosotros, aquí tenéis toda la información respecto a ellos.
Con todo esto, ya podríamos crear una interfaz gráfica, mediante la combinación de los mismos.
Pero, ¿qué hacemos cuando lo que queremos no está disponible en uno de estos objetos incluidos de serie? La respuesta es sencilla: diseñar el nuestro propio a partir de uno de ellos o de una View genérica.
Al crear nuestra propia View, conseguimos un control preciso sobre la apariencia y la funcionalidad de un elemento que incluiremos en la pantalla. Éstas son algunas cosas de las que podemos llegar a hacer:
- Crear una View totalmente personalizada, usando incluso gráficos 2D
- Combinar un grupo de Views en un nuevo componente individual
- Sobreescribir un componente ya existente para dotarlo de funcionalidad añadida o modificada
- Capturar otros eventos en algún componente ya creado
Analicemos primero la aproximación básica. En esta posibilidad, consideramos los siguientes pasos:
- Crear una clase que extienda de una View ya existente (cualquiera de las anteriores por ejemplo)
- Sobreescribir alguno de los métodos de la clase padre. Para saber qué metodos podemos sobreescribir, todos ellos empiezan por ‘on‘, como por ejemplo onDraw, onMeasure, onKeyDown…
- Utilizar la nueva clase.
Pero si esto no nos provee la funcionalidad que buscamos, deberemos acudir a una vista totalmente personalizada, para la cual deberemos seguir los siguientes pasos:
- Crear una clase que extienda de la clase View.
- Proveer un constructor que pueda coger atributos y parámetros del XML o facilitados por nosotros mismos
- Crear nuestros propios escuchadores de eventos, modificadores…
- Sobreescribir los métodos onMeasure (si no lo sobreescribimos, por defecto este método devolverá una vista con tamaño 100 x 100) y onDraw (por defecto no hace nada). De esta forma podremos personalizar lo que mostramos.
- Sobreescribir otros métodos de los que empiezan por ‘on’.
Hemos hablado de los métodos onMeasure y onDraw, pero ¿para qué sirven exactamente?
- onMeasure: Es una pieza crítica en el renderizado entre el componente y su contenedor padre. Deberíamos sobreescribirlo para poder calcular sus dimensiones de forma eficiente.
- onDraw: Nos proporciona un Canvas donde podremos implementar cualquier cosa que no sea gráficos 3D.
Sin embargo, cuando no queremos crear un componente totalmente personalizado y nos gustaría juntar varios componentes reutilizables, utilizaremos un componente compuesto. Para ello:
- El punto de partida habitual suele ser un Layout para nuestra nueva clase
- Crearemos un constructor, de forma similar a anteriormente
- Añadiremos todos los escuchadores que creamos convenientes
- En el caso de que estemos extendiendo de un Layout, podemos olvidarnos de sobreescribir los métodos onDraw y onMesaure (si queremos)
- Sobreescribimos los métodos que empiecen por ‘on’ que necesitemos
Imaginemos que queremos sobreescribir una vista que ya existía. En ese caso deberemos:
- Definir la nueva vista
- Inicializar la clase
- Encarganos de los métodos que debemos sobreescribir
- Usar la nueva vista
Aquí podéis ver un ejemplo perfecto de una nueva vista personalizada. En este caso se trata de un gráfico por sectores.
6. Adaptadores (Adapter)
Hasta ahora hemos visto cómo crear interfaces de usuarios sencillas, donde nosotros indicábamos el layout a utilizar e incluso metíamos nuestras propias vistas personalizadas.
Pero, ¿y si queremos repetir una interfaz repetidas veces según unos datos concretos? Es el caso de una lista de valores, una galería… Y aquí es donde entran en juego los adaptadores.
¿Qué es un adaptador? Un adaptador (clase Adapter) es un puente de comunicación entre un AdapterView (el cual nos permite incluir el layout con la vistas en tiempo de ejecución) y los datos que queremos mostrar en la vista. De esta forma, dinámicamente se irá actualizando la interfaz con nuestros datos.
Como siempre, Android nos facilita algunos ya creados por defecto, los más utilizados. Entre otros, destacan:
- ArrayAdapter: En este caso los datos están formados por un Array, y el procedimiento de mostrar los datos en la vista consiste en utilizar el método toString que todo objeto Java tiene para cada elemento del Array. En el caso de que queramos personalización adicional, deberemos crear una clase que extienda de ArrayAdapter y sobreescribir el método getView, donde podremos modificar cada vista dinámicamente. Un ejemplo ideal es cuando queremos hacer una lista de TextView.
- SimpleCursorAdapter: En este caso los datos están incluidos en un Cursor y será necesario especificar un layout a utilizar para cada fila del cursor. Cuando queramos notificar que han cambiado los datos en el cursos y la interfaz debe actualizarse, bastará llamar al método notifyDataSetChanged.
Por último, mencionar que también podremos gestionar eventos como el pulsado (click) en cada elemento. Para ello basta implementar la clase OnItemClickListener.
Con esto, ya deberíamos ser capaces de no sólo de crear nuestras propias componentes personalizadas (¡echadle un ojo al código del gráfico por sectores!) para la interfaz, sino también crear listas de datos de forma dinámica.
La semana que viene analizaremos otra clase importante, como es el Intent y aprenderemos cómo enviar mensajes broadcast dentro de nuestra aplicación, así como registrarlos. También cómo captar los mensajes que el móvil va enviando a todas las aplicaciones.
¿Estáis poniendo los conceptos en práctica?
Ver la sección Aprende Android en 20 conceptos