Android ofrece un modelo dividido en componentes sofisticado y potente para compilar tu IU, que se basa en
las clases de diseño fundamentales
View
y
ViewGroup
La plataforma incluye un
diversas subclases View
y ViewGroup
compiladas previamente, llamadas widgets y
diseños, respectivamente, que puedes usar para construir tu IU.
Una lista parcial de widgets disponibles incluye Button
; TextView
, EditText
; ListView
; CheckBox
; RadioButton
; Gallery
; Spinner
; y, para objetivos más especiales, AutoCompleteTextView
, ImageSwitcher
y TextSwitcher
.
Entre los diseños disponibles,
LinearLayout
,
FrameLayout
,
RelativeLayout
,
y otros. Para ver más ejemplos, consulta
Diseños comunes.
Si ninguno de los widgets o diseños precompilados satisface tus necesidades, puedes crear los tuyos
la subclase View
. Si solo necesitas hacer pequeños ajustes en un widget existente o
, puedes subclasificar el widget o el diseño, y anular sus métodos.
Crear tus propias subclases de View
te brinda un control preciso sobre el aspecto y
función de un elemento de pantalla. Para tener una idea del control que obtienes con las vistas personalizadas, estos son
algunos ejemplos de lo que puedes hacer con ellas:
-
Puedes crear un tipo de
View
completamente personalizado, por ejemplo, un “volumen controlar” renderizado con gráficos 2D que se asemeja a un control electrónico analógico. -
Puedes combinar un grupo de componentes de
View
en un nuevo componente único, quizás para lo siguiente: crear algo como un cuadro combinado (una combinación de lista emergente y campo de texto de entrada libre), un un control de selección de panel doble (panel izquierdo y derecho con una lista en cada uno donde puedes reasignar qué elemento está en qué lista), etcétera. -
Puedes anular la forma en que se renderiza en la pantalla un componente
EditText
. El La app de ejemplo NotePad usa esto para crear una página de bloc de notas alineada. - Puedes capturar otros eventos, como presionar teclas, y controlarlos de forma personalizada, como como para un juego.
En las siguientes secciones, se explica cómo crear vistas personalizadas y usarlas en tu aplicación. Para
información de referencia detallada, consulta el
Clase View
.
El enfoque básico
Esta es una descripción general de alto nivel de lo que debes saber para crear tu propio View
.
componentes:
-
Extiende una clase o subclase
View
existente con tu propia clase. -
Anula algunos de los métodos de la superclase. Los métodos de la superclase que se anularán comienzan con
on
, por ejemplo,onDraw()
,onMeasure()
, yonKeyDown()
Esto es similar a los eventoson
deActivity
oListActivity
que para el ciclo de vida y otros hooks de funcionalidad. - Usa tu nueva clase de extensión. Cuando termines, puedes usar la nueva clase de extensión en lugar de la vista en la que se basó.
Componentes completamente personalizados
Puedes crear componentes gráficos totalmente personalizados que aparezcan de la forma que prefieras quieren. Tal vez quieras un vúmetro gráfico que se asemeja a un medidor analógico antiguo, o una vista de texto para cantar a coro en el que una pelota que rebota se mueve junto con las palabras mientras usted canta junto con una máquina de karaoke. Es posible que quieras algo que los componentes integrados no pueden hacer, sin importar cómo los combines.
Por suerte, puedes crear componentes que se vean y se comporten como quieras, limitados solo según tu imaginación, el tamaño de la pantalla y la potencia de procesamiento disponible, teniendo en cuenta que tu podría tener que ejecutarse en un dispositivo con mucha menos energía que la de tu computadora estación de trabajo.
Para crear un componente completamente personalizado, ten en cuenta lo siguiente:
-
La vista más genérica que puedes extender es
View
, así que, por lo general, empiezas extendiendo esto para crear tu nuevo supercomponente. - Puedes proporcionar un constructor, que puede tomar atributos y parámetros del XML, y consumir sus propios atributos y parámetros, como el color y el rango del vúmetro o el ancho y el amortiguamiento de la aguja.
- Es probable que quieras crear tus propios objetos de escucha de eventos, descriptores de acceso de propiedades y modificadores, así como comportamiento más sofisticado en tu clase de componente.
-
Es casi seguro que quieras anular
onMeasure()
y que también debas hacerlo anulaonDraw()
si quieres que el componente muestre algo. Si bien ambos tienen comportamiento predeterminado, elonDraw()
predeterminado no hace nada y el valor predeterminadoonMeasure()
siempre establece un tamaño de 100 x 100, que es probable que no desees. -
También puedes anular otros métodos
on
, según sea necesario.
Cómo extender onDraw() y onMeasure()
El método onDraw()
proporciona un
Canvas
en el que puedes
implementar todo lo que desees: gráficos 2D, otros componentes estándares o personalizados, texto con estilo o
cualquier otra cosa que se te ocurra.
onMeasure()
está un poco más involucrado. onMeasure()
es una pieza fundamental
del contrato de renderización entre tu componente y su contenedor. onMeasure()
debe ser
para informar de manera eficiente y precisa las mediciones de las partes contenidas. Este es
un poco más compleja debido a los requisitos de límite del elemento superior, que se pasan al
onMeasure()
y el requisito de llamar al
Método setMeasuredDimension()
con el ancho y la altura medidos una vez que se
calculado. Si no llamas a este método desde un método onMeasure()
anulado,
da como resultado una excepción en el momento de la medición.
En un nivel alto, la implementación de onMeasure()
se ve de la siguiente manera:
-
Se llama al método
onMeasure()
anulado con ancho y alto. que se consideran requisitos de las restricciones de ancho y altura y las mediciones que produzcas.widthMeasureSpec
yheightMeasureSpec
son códigos de número entero que representan dimensiones. Una referencia completa al tipo de restricciones que pueden requerir estas especificaciones en la documentación de referencia enView.onMeasure(int, int)
En esta documentación de referencia, también se explica toda la operación de medición. -
El método
onMeasure()
de tu componente calcula el ancho y la altura de medición, que son necesarias para renderizar el componente. Debe tratar de cumplir con las especificaciones aprobadas a pesar de que puede superarlos. En ese caso, la madre o el padre puede elegir qué hacer, por ejemplo: recortar, desplazarse, arrojar una excepción o pedirle aonMeasure()
que vuelva a intentarlo tal vez con diferentes especificaciones de medición. -
Cuando se calculen el ancho y la altura, llama al
setMeasuredDimension(int width, int height)
con el valor calculado de las mediciones. De lo contrario, se generará una excepción.
Este es un resumen de otros métodos estándar que el framework requiere en las vistas:
Categoría | Métodos | Descripción |
---|---|---|
Creación | Constructores | Hay una forma del constructor a la que se llama cuando se crea la vista a partir de código. y un formulario al que se llama cuando se aumenta la vista desde un archivo de diseño. El segundo formulario analiza y aplica los atributos definidos en el archivo de diseño. |
|
Se llama después de que se aumenta una vista y todos sus elementos secundarios desde XML. | |
Diseño |
|
Se llama para determinar los requisitos de tamaño para esta vista y todos sus elementos secundarios. |
|
Se llama cuando esta vista debe asignar un tamaño y una posición a todos sus elementos secundarios. | |
|
Se llama cuando se cambia el tamaño de esta vista. | |
Dibujo |
|
Se llama cuando la vista debe renderizar su contenido. |
Procesamiento de eventos |
|
Se llama cuando se produce un evento de presión de tecla. |
|
Se llama cuando se produce un evento de activación de tecla. | |
|
Se llama cuando se produce un evento de movimiento de la bola de seguimiento. | |
|
Se llama cuando se produce un evento de movimiento de la pantalla táctil. | |
Enfoque |
|
Se llama cuando la vista gana o pierde el foco. |
|
Se llama cuando la ventana que contiene la vista gana o pierde el foco. | |
Adjuntar |
|
Se llama cuando se adjunta la vista a una ventana. |
|
Se llama cuando se separa la vista de su ventana. | |
|
Se llama cuando se cambia la visibilidad de la ventana que contiene la vista. |
Controles compuestos
Si no quiere crear un componente totalmente personalizado,
pero desea poner
un componente reutilizable que consiste en un grupo de controles existentes y, luego, crea un compuesto
(o control compuesto) podrían ser mejores. En resumen, esto reúne una serie de
vistas o controles atómicos en un grupo lógico de elementos que pueden tratarse como una sola cosa.
Por ejemplo, un cuadro combinado puede ser una combinación de un campo EditText
de una sola línea
y un botón adyacente con una lista emergente adjunta. Si el usuario presiona el botón y selecciona algo de
la lista, propaga el campo EditText
, pero también pueden escribir algo
directamente a EditText
, si así lo prefieren.
En Android, hay otras dos vistas disponibles para hacer esto: Spinner
y
AutoCompleteTextView
En cualquier caso, este concepto de cuadro combinado es un buen ejemplo.
Para crear un componente compuesto, haz lo siguiente:
-
Al igual que con
Activity
, usa el enfoque declarativo (basado en XML) para crear los componentes contenidos o anidarlos de manera programática desde tu código. El punto de partida habitual es unLayout
de algún tipo, así que crea una clase que extienda unLayout
En el caso de un cuadro combinado, puedes usar unLinearLayout
con con orientación horizontal. Se pueden anidar otros diseños en el interior, de modo que el componente compuesto pueda arbitrariamente compleja y estructurada. -
En el constructor de la clase nueva, toma los parámetros que espera la superclase y pásalos
directamente al constructor de la superclase. Luego, puedes configurar las otras vistas
dentro de tu nuevo componente. Aquí es donde creas el campo
EditText
y el lista emergente. Puedes ingresar tus propios atributos y parámetros en el XML que tu puede extraer y usar. -
De forma opcional, crea objetos de escucha para los eventos que puedan generar tus vistas contenidas. Un ejemplo es un
método de objeto de escucha para el elemento de lista, haz clic en el objeto de escucha para actualizar el contenido de la
Es
EditText
si se realiza una selección de lista. -
De forma opcional, crea tus propias propiedades con descriptores de acceso y modificadores. Por ejemplo, deja que la
EditText
se establece inicialmente en el componente y se consulta por su contenido cuando según tus necesidades. -
De manera opcional, anula
onDraw()
yonMeasure()
. Por lo general, esto no es necesario cuando extender unLayout
, ya que el diseño tiene un comportamiento predeterminado que probablemente funcione bien -
De manera opcional, anula otros métodos
on
, comoonKeyDown()
, por ejemplo, para elegir determinados. valores predeterminados de la lista emergente de un cuadro combinado cuando se presiona una tecla determinada.
Usar un Layout
como base para un control personalizado tiene ventajas,
incluidos los siguientes:
- Puedes especificar el diseño con los archivos en formato XML declarativos, al igual que con una pantalla de actividad. o puedes crear vistas de manera programática y anidarlas en el diseño desde tu código.
-
Los métodos
onDraw()
yonMeasure()
, además de la mayoría de los otroson
tienen un comportamiento adecuado, por lo que no es necesario anularlos. - Puedes crear rápidamente vistas compuestas arbitrariamente complejas y reutilizarlas como si fueran un de un solo componente.
Cómo modificar un tipo de vista existente
Si hay un componente que es similar al que deseas, puedes extenderlo y anular
el comportamiento que quieres cambiar. Puedes hacer todo lo que haces con una app
pero, si comienzas con una clase más especializada en la jerarquía View
, podrás
obtener algún comportamiento que haga lo que quieres de forma gratuita.
Por ejemplo, el
Bloc de notas
La app de ejemplo muestra muchos aspectos del uso de la plataforma de Android. Entre ellas, está la ampliación
Vista EditText
para crear un bloc de notas alineado. Este no es un ejemplo perfecto, y las APIs para
hacer esto puede cambiar, pero demuestra los principios.
Si aún no lo hiciste, importa el ejemplo del Bloc de notas a Android Studio o consulta la
desde el vínculo proporcionado. En particular, consulta la definición de LinedEditText
.
en la
NoteEditor.java
.
A continuación, encontrarás algunos aspectos que debes tener en cuenta en este archivo:
-
La definición
La clase se define con la siguiente línea:
public static class LinedEditText extends EditText
LinedEditText
se define como una clase interna dentro deNoteEditor
. pero es pública, por lo que se puede acceder a ella comoNoteEditor.LinedEditText
desde fuera de la claseNoteEditor
.Además,
LinedEditText
esstatic
, lo que significa que no genera la denominados "métodos sintéticos" que le permiten acceder a datos de la clase superior. Esto significa que Se comporta como una clase independiente en lugar de como algo muy relacionado conNoteEditor
. Esta es una forma más limpia de crear clases internas si no necesitan acceso al estado desde el externa. Mantiene pequeña la clase generada y permite que se use fácilmente desde otros .LinedEditText
extiendeEditText
, que es la vista que se personalizará en este caso. Cuando termines, la clase nueva puede reemplazar a unaEditText
normal vista. -
Inicialización de la clase
Como siempre, se llama primero a la superclase. Este no es un constructor predeterminado, uno parametrizado. Se crea el
EditText
con estos parámetros cuando es inflado a partir de un archivo de diseño XML. Por lo tanto, el constructor debe tomarlas y pasarlas el constructor de la superclase. -
Métodos anulados
En este ejemplo, solo se anula el método
onDraw()
, pero es posible que debas anular otros cuando crees tus propios componentes personalizados.Para esta muestra, anular el método
onDraw()
te permite pintar las líneas azules en el lienzo de vistas deEditText
. El lienzo se pasa al elementoonDraw()
. Se llama al métodosuper.onDraw()
antes de antes de que termine el método. Se debe invocar el método de la superclase. En este caso, debes invocarlo al final, después de pintas las líneas que quieres incluir. -
Componente personalizado
Ahora tienes tu componente personalizado, pero ¿cómo puedes usarlo? En el ejemplo del Bloc de notas, la el componente personalizado se usa directamente desde el diseño declarativo, así que
note_editor.xml
enres/layout
carpeta:<view xmlns:android="http://schemas.android.com/apk/res/android" class="com.example.android.notepad.NoteEditor$LinedEditText" android:id="@+id/note" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/transparent" android:padding="5dp" android:scrollbars="vertical" android:fadingEdge="vertical" android:gravity="top" android:textSize="22sp" android:capitalize="sentences" />
El componente personalizado se crea como una vista genérica en el XML y se especifica la clase. con el paquete completo. Se hace referencia a la clase interna que defines usando el
NoteEditor$LinedEditText
, que es una forma estándar de referirse a la en el lenguaje de programación Java.Si tu componente de vista personalizada no está definido como una clase interna, puedes declarar la vista. con el nombre del elemento XML y excluye el atributo
class
. Por ejemplo:<com.example.android.notepad.LinedEditText id="@+id/note" ... />
Observa que la clase
LinedEditText
ahora es un archivo de clase independiente. Cuando está anidada en la claseNoteEditor
, esta técnica no funciona.Los demás atributos y parámetros de la definición son los que se pasan al de componentes y, luego, se pasa al constructor
EditText
. son los mismos parámetros que usas para una vista deEditText
. Es posible agregar tus propios parámetros también.
Crear componentes personalizados es tan complicado como desees.
Un componente más sofisticado puede anular aún más métodos on
e introducir su
propios métodos auxiliares, lo que permite personalizar sustancialmente sus propiedades y comportamiento. El único límite es el
imaginación y lo que necesitas que haga el componente.