Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Una de las reglas más importantes en términos de diseño de aplicación es la unicidad: si una misma
funcionalidad está presente en varias pantallas de una aplicación, debe presentar el mismo diseño
para todas las pantallas.
Para evitar al desarrollador tener que producir el mismo código en distintas ubicaciones, el sistema
Android le ofrece la posibilidad de diseñar sus propios componentes de interfaz, que podrán utilizarse
con la misma facilidad que los componentes nativos de la plataforma como, por
ejemplo, ed itText,ListView, etc.
Todos los componentes, como hemos visto en el capítulo Los fundamentos, forman parte del
paquete android.widgety es posible sobrecargarlos.
Por regla general, el layout del componente sobrecargado no se modifica en sí mismo, sino que las
modificaciones realizadas en este contexto son por lo general reducidas. Basta, por tanto, con crear
una nueva clase, que extenderá de la clase del componente que se ha seleccionado, y agregar los
métodos que deseemos.
package es.midominio.miAplicacion;
import android.widget.AutoCompleteTextView;
[...]
public class MiCustomAutoComplete extends AutoCompleteTextView{
...
}
Esta clase deberá proveer dos constructores: uno que se utiliza cuando se declara una instancia de
la clase en el código y otra que se utiliza específicamente cuando el componente se declara en un
archivo de recursos (un archivo de layout de una actividad, por ejemplo).
En ambos casos, resulta obligatorio invocar al constructor correspondiente del padre, llamada que
debe ser la primera instrucción del constructor.
El primer constructor, para una declaración directa en el código, recibe como único parámetro un
objeto Context.
Según la personalización deseada, una vez definidos los constructores, basta con sobrecargar los
métodos correspondientes, consultando la documentación del componente nativo extendido.
<es.midominio.miAplicacion.MiCustomAutoComplete
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
El uso del componente en el código de la actividad no difiere del uso de un componente nativo: la
referencia al componente se realiza utilizando el método findViewById.
Uno de los principales intereses para sobrecargar componentes nativos del sistema reside en la
posibilidad que esto ofrece para definir atributos personalizados. Estos atributos pueden, a
continuación, recibir un valor igual que los atributos nativos mediante la etiqueta XML
correspondiente del componente.
Para utilizar estos atributos personalizados en un archivo de layout, es preciso declarar el espacio
de nombres correspondiente (el nombre del paquete de la solución) en el archivo XML dellayout,
de forma análoga al tradicional espacio de nombres " a ndroid".
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:capitulo8="http://schemas.android.com/apk/res/
es.midominio.MiAplicacion"
android:layout_width="match_parent"
android:layout_height="match_parent">
<es.midominio.miAplicacion.MiCustomAutoComplete
android:layout_width="fill_parent"
android:layout_height="wrap_content"
capitulo8:miAtributoCustom_1="valor_1"
capitulo8:miAtributoCustom_2="true"/>
</RelativeLayout>
Es posible recuperar los atributos definidos por el componente en la etiqueta XML a nivel de la clase
del componente, típicamente en el constructor. Esta recuperación se realiza en dos tiempos:
El segundo parámetro, una tabla de valores enteros, representa la lista de atributos que se
desean recuperar.
Este segundo parámetro debe explicitarse: se trata de hecho de una tabla con los identificadores
generados en tiempo de compilación de la solución, y que podemos encontrar en el archivo R.java,
dentro de la carpeta gende la solución.
TypedArray customAttributes =
context.obtainStyledAttributes(attr,
R.styleable.misAtributosCustoms);
...
}
Por último, resulta muy sencillo obtener los valores de los distintos atributos utilizando el
objeto TypedArrayque devuelve el método: en función del tipo definido, basta con utilizar el
método correspondiente.
En este caso, en lugar de sobrecargar directamente un componente, resulta más adecuado extender
uno de los componentes layout - los componentes l inearlayout o relativelayout, por
ejemplo - que realizarán la misma representación del componente, y exponer los métodos necesarios
para el funcionamiento del componente.
En esta arquitectura, los componentes puede declararse bien directamente en el código o bien
utilizando un archivo XML de layout.
En cualquier caso, se recomienda encarecidamente basarse en un objeto de tipo View, que aportará
los procesamientos de bajo nivel, siendo lo más genérico posible. Además de la declaración de los
constructores vistos anteriormente, la parte esencial del trabajo será, en este caso, la escritura de
los métodos o nDraw()y onMeasure(): el método onDraw()se encarga de "dibujar" la interfaz
gráfica por pantalla, el método onMeasure()es responsable de determinar las dimensiones (ancho
y alto) del componente creado.
a. Implementar onDraw()
La firma completa del método es la siguiente:
El objeto de tipo Canvasque se pasa como parámetro es la instancia que incluirá la llamada a los
métodos encargados de dibujar las formas que deseemos integrar en la vista. Estas formas podrán
ser primitivas geométricas (línea, rectángulo, arco, punto, etc.), pero también objetos de tipo bitmap
así como texto.
Por último, para dibujar el componente, es necesario definir al menos un objeto de tipo P aint, que
se corresponde con un pincel virtual. La clase Paintpermite definir el estilo del pincel, el color, los
atributos de texto, así como la presencia de sombra (¡automática!), el antialiasing, etc.
El método onDr aw() se invoca la primera vez que la vista debe dibujarse. Para forzar, a
continuación, que se invoque al método onDraw(), es preciso invocar al
método in validate()de la vista. En el caso de que la demanda se realice en un thread
separado (es decir, en un thread diferente a UIThread), es preciso invocar
a pos tInvalidate(); la llamada será, entonces, asíncrona.
b. Implementar onMeasure()
El objetivo de este método es calcular el ancho y alto de la vista e informar al padre de la vista en
cuestión. El hecho de informar al padre de la vista, una vez realizado el cálculo, es obligatorio, y su
omisión generará una excepción de tipo I llegalStateException.
La firma de onMeasure()es la siguiente:
Para dispositivos que ejecuten una versión de Android anterior a la versión 3.2 (API 13), es preciso
invocar a los métodos ge tWidth()y getHeight()del objeto Display.
Para los sistemas que trabajan con Android 3.2 o superior, el método getSize() del
objeto Displayreemplaza a los métodos getWidth()y getHeight().
if (android.os.Build.VERSION.SDK_INT >=
android.os.Build.VERSION_CODES.HONEYCOMB_MR2) {
Point size = new Point();
display.getSize(size);
screenWidth = size.x;
screenHeight = size.y;
}
else {
screenWidth = display.getWidth();
screenHeight = display.getHeight();
}
}