Una vista personalizada bien diseñada es similar a cualquier otra clase bien diseñada. Encapsula un conjunto específico de funcionalidades en una interfaz fácil de usar, usa la CPU y la memoria de manera eficiente, etc. Sin embargo, además de ser una clase bien diseñada, una vista personalizada debe tener las siguientes características:
- Cumplir con los estándares de Android
- Proporcionar atributos con estilo personalizado que funcionen con diseños XML de Android
- Enviar eventos de accesibilidad
- Ser compatible con múltiples plataformas de Android
El marco de trabajo de Android proporciona un conjunto de clases base y etiquetas XML para ayudarte a crear una vista que cumpla con todos estos requisitos. En esta lección, se analiza cómo usar el marco de trabajo de Android para crear la funcionalidad principal de una clase de vista.
Fuera de esta lección, encontrarás información adicional relacionada en Componentes personalizados.
Cómo crear una subclase para una vista
Todas las clases de vista definidas en el marco de trabajo de Android extienden la View
. Tu vista personalizada también puede extender View
directamente, o puedes ahorrar tiempo extendiendo una de las subclases de vista existentes, como Button
.
Para permitir que Android Studio interactúe con tu vista, como mínimo, debes proporcionar un constructor que tome un Context
y un objeto AttributeSet
como parámetros.
Este constructor permite que el editor de diseño cree y edite una instancia de tu vista.
Kotlin
class PieChart(context: Context, attrs: AttributeSet) : View(context, attrs)
Java
class PieChart extends View { public PieChart(Context context, AttributeSet attrs) { super(context, attrs); } }
Cómo definir atributos personalizados
Para agregar una View
integrada a la interfaz de usuario, debes especificarla en un elemento XML y controlar su apariencia y comportamiento con los atributos del elemento. Las vistas personalizadas diseñadas correctamente también se pueden agregar a través de XML, y es posible agregarles estilo del mismo modo. Para habilitar este comportamiento en tu vista personalizada, haz lo siguiente:
- Define atributos personalizados para tu vista en un elemento del recurso
<declare-styleable>
. - Especifica valores para los atributos en tu diseño XML.
- Recupera valores de atributos en el tiempo de ejecución.
- Aplica los valores de atributo recuperados en tu vista.
En esta sección, se analiza cómo definir atributos personalizados y especificar sus valores. En la siguiente sección, se trata la recuperación y la aplicación de los valores en el tiempo de ejecución.
Para definir atributos personalizados, agrega recursos <declare-styleable>
a tu proyecto. Es común colocar estos recursos en un archivo res/values/attrs.xml
. El siguiente es un ejemplo de un archivo attrs.xml
:
<resources> <declare-styleable name="PieChart"> <attr name="showText" format="boolean" /> <attr name="labelPosition" format="enum"> <enum name="left" value="0"/> <enum name="right" value="1"/> </attr> </declare-styleable> </resources>
En este código, se declaran dos atributos personalizados, showText
y labelPosition
, que pertenecen a una entidad con estilo llamada PieChart
. El nombre de la entidad con estilo es, por convención, el mismo nombre que el de la clase que define la vista personalizada. Aunque no es estrictamente necesario seguirla, muchos editores de códigos populares dependen de esta convención de nomenclatura para proporcionar la finalización de la declaración.
Una vez que hayas definido los atributos personalizados, podrás usarlos en archivos XML de diseño al igual que los atributos integrados. La única diferencia es que tus atributos personalizados pertenecen a un espacio de nombres diferente. En lugar de pertenecer al espacio de nombres http://schemas.android.com/apk/res/android
, pertenecen a http://schemas.android.com/apk/res/[your package name]
. Por ejemplo, aquí se muestra cómo usar los atributos definidos para PieChart
:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:custom="http://schemas.android.com/apk/res/com.example.customviews"> <com.example.customviews.charting.PieChart custom:showText="true" custom:labelPosition="left" /> </LinearLayout>
Para evitar tener que repetir el URI de espacio de nombres largo, en el ejemplo, se usa una directiva xmlns
. Esta directiva asigna el alias custom
al espacio de nombres http://schemas.android.com/apk/res/com.example.customviews
. Puedes elegir cualquier alias que quieras para tu espacio de nombres.
Observa el nombre de la etiqueta XML que agrega la vista personalizada al diseño. Es el nombre completo de la clase de vista personalizada. Si tu clase de vista es una clase interna, debes calificarla con el nombre de la clase externa de la vista.
Por ejemplo, la clase PieChart
tiene una clase interna denominada PieView
. Para usar los atributos personalizados de esta clase, debes usar la etiqueta com.example.customviews.charting.PieChart$PieView
.
Cómo aplicar atributos personalizados
Cuando se crea una vista desde un diseño XML, todos los atributos de la etiqueta XML se leen del paquete de recursos y se pasan al constructor de la vista como un AttributeSet
.
Aunque es posible leer valores de AttributeSet
directamente, esta opción tiene algunas desventajas:
- No se resuelven las referencias de recursos dentro de los valores del atributo.
- No se aplican los estilos.
En su lugar, pasa el AttributeSet
a obtainStyledAttributes()
.
Este método muestra un arreglo de valores TypedArray
con referencias resueltas y estilos aplicados.
El compilador de recursos de Android hace un gran trabajo para facilitar la llamada a obtainStyledAttributes()
. Para cada recurso <declare-styleable>
del directorio de recursos, el R.java generado define tanto un arreglo de ID de atributos como un conjunto de constantes que definen el índice de cada atributo del arreglo. Las constantes predefinidas se usan para leer los atributos desde TypedArray
. A continuación, se muestra cómo la clase PieChart
lee sus atributos:
Kotlin
init { context.theme.obtainStyledAttributes( attrs, R.styleable.PieChart, 0, 0).apply { try { mShowText = getBoolean(R.styleable.PieChart_showText, false) textPos = getInteger(R.styleable.PieChart_labelPosition, 0) } finally { recycle() } } }
Java
public PieChart(Context context, AttributeSet attrs) { super(context, attrs); TypedArray a = context.getTheme().obtainStyledAttributes( attrs, R.styleable.PieChart, 0, 0); try { mShowText = a.getBoolean(R.styleable.PieChart_showText, false); textPos = a.getInteger(R.styleable.PieChart_labelPosition, 0); } finally { a.recycle(); } }
Ten en cuenta que los objetos TypedArray
son un recurso compartido y se deben reciclar después del uso.
Cómo agregar propiedades y eventos
Los atributos son una forma eficaz de controlar el comportamiento y la apariencia de las vistas, pero solo se pueden leer si se inicializó la vista. Con el fin de proporcionar un comportamiento dinámico, expón un par captador y establecedor de propiedad para cada atributo personalizado. En el siguiente fragmento, se muestra cómo PieChart
expone una propiedad denominada showText
:
Kotlin
fun isShowText(): Boolean { return mShowText } fun setShowText(showText: Boolean) { mShowText = showText invalidate() requestLayout() }
Java
public boolean isShowText() { return mShowText; } public void setShowText(boolean showText) { mShowText = showText; invalidate(); requestLayout(); }
Ten en cuenta que setShowText
llama a invalidate()
y requestLayout()
. Estas llamadas son cruciales para garantizar que la vista se comportará de manera confiable. Debes invalidar la vista después de cualquier cambio en las propiedades que pudiera modificar la apariencia para que el sistema sepa que deberá volver a generarla. Del mismo modo, si cambia una propiedad que podría afectar el tamaño o la forma de la vista, deberás solicitar un nuevo diseño. Si olvidas estas llamadas a métodos, se pueden generar errores difíciles de encontrar.
Las vistas personalizadas también deben permitir que los objetos de escucha de eventos comuniquen eventos importantes. Por ejemplo, PieChart
expone un evento personalizado denominado OnCurrentItemChanged
para notificar a los objetos de escucha que el usuario rotó el gráfico circular para enfocarse en un nuevo sector circular.
Es fácil olvidarse de exponer propiedades y eventos, en especial cuando eres el único usuario de la vista personalizada. Si te tomas el tiempo para definir en detalle la interfaz de la vista, se reducirán los costos de mantenimiento futuros. Una regla práctica es exponer siempre cualquier propiedad que afecte la apariencia visible o el comportamiento de la vista personalizada.
Cómo crear diseños para accesibilidad
La vista personalizada debe admitir la mayor cantidad posible de usuarios, incluidos los que tienen discapacidades que les impiden ver o usar una pantalla táctil. Para admitir usuarios con discapacidades, haz lo siguiente:
- Etiqueta los campos de entrada con el atributo
android:contentDescription
. - Envía eventos de accesibilidad llamando a
sendAccessibilityEvent()
cuando corresponda. - Admite controles alternativos, como pad direccional y bola de seguimiento.
Para obtener más información sobre cómo crear vistas accesibles, consulta Cómo generar accesibilidad a las aplicaciones en la Guía para desarrolladores de Android.