miércoles, 29 de octubre de 2014

Controles personalizados: Extender controles en Android



En apartados anteriores hemos conocido y aprendido a utilizar muchos de los controles que proporciona Android en su SDK. Con la ayuda de estos controles podemos diseñar interfaces gráficas de lo más variopinto pero en ocasiones, si queremos dar un toque especial y original a nuestra aplicación, o simplemente si necesitamos cierta funcionalidad no presente en los componentes estándar de Android, nos vemos en la necesidad de crear nuestros propios controles personalizados, diseñados a la medida de nuestros requisitos.

Android admite por supuesto crear controles personalizados, y permite hacerlo de diferentes formas:

1. Extendiendo la funcionalidad de un control ya existente.
2. Combinando varios controles para formar otro más complejo.
3. Diseñando desde cero un nuevo control.

En este primer apartado sobre el tema vamos a hablar de la primera opción, es decir, vamos a ver cómo podemos crear un nuevo control partiendo de la base de un control ya existente. A modo de ejemplo, vamos a extender el control EditText (cuadro de texto) para que muestre en todo momento el número de caracteres que contiene a medida que se escribe en él. Intentaríamos emular algo así como el editor de mensajes SMS del propio sistema operativo, que nos avisa del número de caracteres que contiene el mensaje.

En la esquina superior derecha del cuadro de texto vamos a mostrar el número de caracteres del mensaje de texto introducido, que irá actualizándose a medida que modificamos el texto. Para empezar, vamos a crear una nueva clase java que extienda del control que queremos utilizar como base, en este caso EditText.


Tras esto, sobrescribiremos siempre los tres constructores heredados, donde por el momento nos limitaremos a llamar al mismo constructor de la clase padre.


Por último el paso más importante. Dado que queremos modificar el aspecto del control para añadir el contador de caracteres tendremos que sobrescribir el evento onDraw(), que es llamado por Android cada vez que hay que redibujar el control en pantalla. Este método recibe como parámetro un objeto Canvas, que no es más que el "lienzo" sobre el que podemos dibujar todos los elementos extra necesarios en el control. El objeto Canvas, proporciona una serie de métodos para dibujar cualquier tipo de elemento (líneas, rectángulos, elipses, texto, bitmaps, …) sobre el espacio ocupado por el control. En nuestro caso tan sólo vamos a necesitar dibujar sobre el control un rectángulo que sirva de fondo para el contador y el texto del contador con el número de caracteres actual del cuadro de texto. No vamos a entrar en muchos detalles sobre la forma de dibujar gráficos ya que ése será tema de otro apartado, pero vamos a ver al menos las acciones principales.

En primer lugar definiremos los "pinceles" (objetos Paint) que utilizaremos para dibujar, uno de ellos (p1) de color negro y relleno sólido para el fondo del contador, y otro (p2) de color blanco para el texto. Para configurar los colores, el estilo de fondo y el tamaño del texto utilizaremos los métodos setColor(), setStyle() y setTextSize() respectivamente:


Dado que estos elementos tan sólo hará falta crearlos la primera vez que se dibuje el control, para evitar trabajo innecesario no incluiremos su definición en el método onDraw(), sino que los definiremos como atributos de la clase y los inicializaremos en el constructor del control (en los tres).

Una vez definidos los diferentes pinceles necesarios, dibujaremos el fondo y el texto del contador mediante los métodos drawRect() y drawText(), respectivamente, del objeto canvas recibido en el evento. Lo único a tener en cuenta es que todos estos métodos de dibujo reciben las unidades en pixeles y por tanto si utilizamos valores fijos tendremos problemas al visualizar los resultados en pantallas con distintas densidades de píxeles.

Para evitar esto en lo posible, tendremos que convertir nuestros valores de píxeles a algún valor dependiente de la densidad de la pantalla, lo que en Android podemos conseguir multiplicando siempre nuestros píxeles por un factor de escala que podemos obtener mediante los métodos getResources(). getDisplayMetrics().density. Tras obtener este valor, multiplicaremos por él todas nuestras unidades en píxeles para conseguir los mismos efectos en cualquier pantalla. Veamos cómo quedaría el código completo:


Como puede comprobarse, a estos métodos se les pasan como parámetro las coordenadas del elemento a dibujar relativas al espacio ocupado por el control y el pincel a utilizar en cada caso.

Hecho esto, ya tenemos finalizado nuestro cuadro de texto personalizado con contador de caracteres. Para añadirlo a la interfaz de nuestra aplicación lo incluiremos en el layout XML de la ventana tal como haríamos con cualquier otro control, teniendo en cuenta que deberemos hacer referencia a él con el nombre completo de la nueva clase creada (incluido el paquete java), que en mi caso particular sería net.sgoliver. ExtendedEditText.


Para finalizar, veamos cómo quedaría nuestro control en dos dispositivos distintos con densidades de pantalla diferentes.

En Android 2 con densidad de pantalla baja:


Y en Android 4 con densidad de pantalla alta:


En el siguiente apartado veremos cómo crear un control personalizado utilizando la segunda de las opcionesexpuestas, es decir, combinando varios controles ya existentes. Comentaremos además como añadir eventos y propiedades personalizadas a nuestro control y cómo hacer referencia a dichas propiedades desde su definición XML.



Saludos compañeros, aprovechen la información.







No hay comentarios:

Publicar un comentario en la entrada