Algunos usuarios de dispositivos Android tienen necesidades de accesibilidad diferentes de otros. Para ayudar a un grupo determinado de la población que comparte una necesidad de accesibilidad, el framework de Android brinda a los desarrolladores la capacidad de crear un servicio de accesibilidad, que les presenta el contenido de las apps y las opera en su nombre.
Android proporciona varios servicios de accesibilidad del sistema, incluidos los siguientes:
- TalkBack: Ayuda a las personas con visión reducida o ciegas. Anuncia el contenido a través de una voz sintetizada y realiza acciones en una app en respuesta a los gestos del usuario.
- Accesibilidad mejorada: Ayuda a las personas con discapacidades motoras. Destaca elementos interactivos y realiza acciones como respuesta cuando el usuario presiona un botón. Permite controlar el dispositivo con solo 1 o 2 botones.
Para ayudar a las personas con necesidades de accesibilidad a usar tu app como corresponde, esta debe seguir las prácticas recomendadas que se describen en esta página, que se basan en los lineamientos clave incluidos en Cómo mejorar la accesibilidad de las apps.
Cada una de las siguientes prácticas recomendadas puede mejorar la accesibilidad de tu app:
- Etiqueta los elementos
- Los usuarios deben poder comprender el contenido y el propósito de cada elemento de la IU interactivo y significativo en tu app.
- Usa o extiende widgets del sistema
- Compila a partir de los elementos de vista que incluye el framework, en lugar de crear tus propias vistas personalizadas. Las clases de vista y widget del framework ya proporcionan la mayoría de las capacidades de accesibilidad que necesita tu app.
- Utiliza señales que no hagan uso del color
- Los usuarios deben poder distinguir claramente entre categorías de elementos en una IU. Para ello, usa patrones y la posición, además del color, para expresar estas diferencias.
- Mejora la accesibilidad del contenido multimedia
- Agrega descripciones al contenido de video o audio de tu app a fin de que los usuarios que lo consuman no tengan que depender por completo de señales visuales o sonoras.
Etiqueta elementos
Es importante brindarles a los usuarios etiquetas útiles y descriptivas para cada elemento de la IU interactivo de tu app. En cada etiqueta, se debe explicar el significado y el propósito de un elemento específico. Los lectores de pantalla como TalkBack pueden leerles las etiquetas a los usuarios que dependen de estos servicios.
En la mayoría de los casos, debes especificar la descripción de un elemento de la IU determinado en el archivo de recursos de diseño que lo contiene. Aunque, por lo general, debes agregar etiquetas con el atributo contentDescription
, como se explica en la guía sobre cómo mejorar la accesibilidad de las apps, hay otras técnicas de etiquetado que debes tener en cuenta, como se describe en las siguientes secciones.
Elementos editables
Cuando etiquetas elementos editables, como objetos EditText
, resulta útil mostrar texto que brinde ejemplos de entradas válidas en el elemento, además de hacer que este texto de ejemplo esté disponible para los lectores de pantalla. En estos casos, puedes usar el atributo android:hint
, como se muestra en el siguiente fragmento:
<!-- The hint text for en-US locale would be "Apartment, suite, or building". --> <EditText android:id="@+id/addressLine2" android:hint="@string/aptSuiteBuilding" ... />
En este caso, el objeto View
debe tener su atributo android:labelFor
establecido en el ID del elemento EditText
. Si deseas obtener más información, consulta la sección en la que se explica cómo etiquetar pares de elementos en los que uno describe al otro.
Pares de elementos en los que uno describe al otro
Es común que un elemento EditText
determinado tenga un objeto View
correspondiente que describa el contenido que los usuarios deben ingresar en el elemento EditText
. En los dispositivos con Android 4.2 (API nivel 17) o una versión posterior, puedes establecer el atributo android:labelFor
del objeto View
para indicar esta relación.
En el siguiente fragmento, se muestra un ejemplo de cómo etiquetar estos pares de elementos:
<!-- Label text for en-US locale would be "Username:" --> <TextView android:id="@+id/usernameLabel" ... android:text="@string/username" android:labelFor="@+id/usernameEntry" /> <EditText android:id="@+id/usernameEntry" ... /> <!-- Label text for en-US locale would be "Password:" --> <TextView android:id="@+id/passwordLabel" ... android:text="@string/password android:labelFor="@+id/passwordEntry" /> <EditText android:id="@+id/passwordEntry" android:inputType="textPassword" ... />
Elementos de una colección
Cuando agregas etiquetas a los elementos de una colección, cada etiqueta debe ser única. De esa manera, los servicios de accesibilidad del sistema pueden hacer referencia a exactamente un elemento en la pantalla cuando leen una etiqueta. Esta correspondencia permite que los usuarios sepan cuándo completaron el ciclo de la IU o cuándo trasladaron el enfoque a un elemento que ya descubrieron.
En particular, debes incluir texto adicional o información contextual en los elementos dentro de diseños reutilizados, como los objetos RecyclerView
, a fin de que cada elemento secundario se pueda identificar de manera única.
Para ello, establece la descripción del contenido como parte de tu implementación del adaptador, como se muestra en el siguiente fragmento de código:
Kotlin
data class MovieRating(val title: String, val starRating: Integer) class MyMovieRatingsAdapter(private val myData: Array<MovieRating>): RecyclerView.Adapter<MyMovieRatingsAdapter.MyRatingViewHolder>() { class MyRatingViewHolder(val ratingView: ImageView) : RecyclerView.ViewHolder(ratingView) override fun onBindViewHolder(holder: MyRatingViewHolder, position: Int) { val ratingData = myData[position] holder.ratingView.contentDescription = "Movie ${position}: " + "${ratingData.title}, ${ratingData.starRating} stars" } }
Java
public class MovieRating { private String title; private int starRating; // ... public String getTitle() { return title; } public int getStarRating() { return starRating; } } public class MyMovieRatingsAdapter extends RecyclerView.Adapter<MyAdapter.MyRatingViewHolder> { private MovieRating[] myData; public static class MyRatingViewHolder extends RecyclerView.ViewHolder { public ImageView ratingView; public MyRatingViewHolder(ImageView iv) { super(iv); ratingView = iv; } } @Override public void onBindViewHolder(MyRatingViewHolder holder, int position) { MovieRating ratingData = myData[position]; holder.ratingView.setContentDescription("Movie " + position + ": " + ratingData.getTitle() + ", " + ratingData.getStarRating() + " stars") } }
Grupos de contenido relacionado
Si tu app muestra varios elementos de la IU que forman un grupo natural, como detalles de una canción o atributos de un mensaje, organiza estos elementos dentro de un contenedor, que generalmente es una subclase de ViewGroup
. Establece el atributo android:screenReaderFocusable
del objeto del contenedor en true
y el atributo android:focusable
de cada objeto interno en false
. De este modo, los servicios de accesibilidad pueden presentar las descripciones del contenido de los elementos internos, una después de la otra, en un solo anuncio.
Esta consolidación de elementos relacionados ayuda a los usuarios de la tecnología de accesibilidad a descubrir la información que se muestra en la pantalla de manera más eficiente.
El siguiente fragmento incluye elementos de contenido que se relacionan entre sí. Por ello, el elemento de contenedor, una instancia de ConstraintLayout
, tiene su atributo android:screenReaderFocusable
establecido en true
y cada uno de los elementos TextView
internos tiene su atributo android:focusable
establecido en false
:
<!-- In response to a single user interaction, accessibility services announce both the title and the artist of the song. --> <ConstraintLayout android:id="@+id/song_data_container" ... android:screenReaderFocusable="true"> <TextView android:id="@+id/song_title" ... android:focusable="false" android:text="@string/my_song_title" /> <TextView android:id="@+id/song_artist" android:focusable="false" android:text="@string/my_songwriter" /> </ConstraintLayout>
Debido a que los servicios de accesibilidad anuncian las descripciones de los elementos internos en una sola frase, es importante que cada descripción sea lo más breve posible y, al mismo tiempo, transmita el significado del elemento.
Etiqueta de grupo personalizado
Si lo deseas, puedes anular la agrupación y el orden predeterminados de la plataforma de descripciones de los elementos internos de un grupo. Para ello, proporciona una descripción de contenido para el grupo.
En el siguiente fragmento, se muestra un ejemplo de una descripción de grupo personalizada:
<!-- In response to a single user interaction, accessibility services announce the custom content description for the group. --> <ConstraintLayout android:id="@+id/song_data_container" ... android:screenReaderFocusable="true" android:contentDescription="@string/title_artist_best_song"> <TextView android:id="@+id/song_title" ... <!-- Content ignored by accessibility services --> android:text="@string/my_song_title" /> <TextView android:id="@+id/song_artist" <!-- Content ignored by accessibility services --> android:text="@string/my_songwriter" /> </ConstraintLayout>
Grupos anidados
Si la interfaz de tu app presenta información multidimensional, como una lista diaria de eventos de un festival, usa el atributo android:screenReaderFocusable
en los contenedores del grupo interno. Este esquema de etiquetas ofrece un buen equilibrio entre la cantidad de anuncios necesarios para descubrir el contenido de la pantalla y la longitud de cada anuncio.
En el siguiente fragmento, se muestra un método de grupos de etiquetado dentro de grupos de mayor tamaño:
<!-- In response to a single user interaction, accessibility services announce the events for a single stage only. --> <ConstraintLayout android:id="@+id/festival_event_table" ... > <ConstraintLayout android:id="@+id/stage_a_event_column" android:screenReaderFocusable="true"> <!-- UI elements that describe the events on Stage A. --> </ConstraintLayout> <ConstraintLayout android:id="@+id/stage_b_event_column" android:screenReaderFocusable="true"> <!-- UI elements that describe the events on Stage B. --> </ConstraintLayout> </ConstraintLayout>
Encabezados dentro de texto
Algunas apps usan encabezados para resumir grupos de texto que se muestran en la pantalla. Si un elemento View
específico representa un encabezado, puedes indicar su objetivo para los servicios de accesibilidad. Para ello, establece el atributo android:accessibilityHeading
del elemento en true
.
Los usuarios de los servicios de accesibilidad pueden elegir navegar entre encabezados, en lugar de hacerlo entre párrafos o palabras. Esta flexibilidad mejora la experiencia de navegación del texto.
Títulos del panel de accesibilidad
En Android 9 (API nivel 28) y versiones posteriores, puedes proporcionar títulos accesibles para los paneles de una pantalla. Para los fines de la accesibilidad, un panel es una parte de una ventana distinta a nivel visual, como el contenido de un fragmento. Si deseas que los servicios de accesibilidad comprendan cómo un panel se comporta de manera similar a una ventana, debes proporcionar títulos descriptivos para los paneles de tu app. Luego, los servicios de accesibilidad pueden proporcionar información más detallada a los usuarios cuando la apariencia o el contenido de un panel cambian.
Para especificar el título de un panel, usa el atributo android:accessibilityPaneTitle
, como se muestra en el siguiente fragmento:
<!-- Accessibility services receive announcements about content changes that are scoped to either the "shopping cart view" section (top) or "browse items" section (bottom) --> <MyShoppingCartView android:id="@+id/shoppingCartContainer" android:accessibilityPaneTitle="@string/shoppingCart" ... /> <MyShoppingBrowseView android:id="@+id/browseItemsContainer" android:accessibilityPaneTitle="@string/browseProducts" ... />
Elementos decorativos
Si un elemento de tu IU solo existe para brindar espacio visual o mejorar la apariencia, establece su atributo android:contentDescription
en "null"
.
Si tu app solo admite dispositivos con Android 4.1 (API nivel 16) y versiones posteriores, puedes establecer los atributos android:importantForAccessibility
de estos elementos meramente decorativos en "no"
.
Extiende los widgets del sistema
Punto clave: Cuando diseñes la IU de tu app, usa o extiende los widgets proporcionados por el sistema que estén lo más abajo posible en la jerarquía de clases de Android. Los widgets proporcionados por el sistema que están muy por debajo de la jerarquía ya tienen la mayoría de las capacidades de accesibilidad que necesita tu app. Es más fácil extender estos widgets que crear unos nuevos de las clases más genéricas View
, ViewCompat
, Canvas
y CanvasCompat
.
Si debes extender View
o Canvas
directamente, lo que podría ser necesario en niveles de juegos o experiencias muy personalizadas, consulta Cómo mejorar la accesibilidad de las vistas personalizadas.
En esta sección, se describe cómo implementar un tipo especial de Switch
llamado TriSwitch
. Un objeto TriSwitch
funciona de manera similar a un objeto Switch
, excepto que cada instancia de TriSwitch
le permite al usuario alternar entre 3 estados posibles.
Extiende desde la jerarquía de clases
El objeto Switch
hereda de varias clases de IU del framework en su jerarquía:
View ↳ TextView ↳ Button ↳ CompoundButton ↳ Switch
Lo ideal es que la nueva clase TriSwitch
se extienda directamente desde la clase Switch
. De esta manera, el framework de accesibilidad de Android proporciona la mayoría de las capacidades de accesibilidad que necesita la clase TriSwitch
:
- Acciones de accesibilidad: Informan al sistema cómo los servicios de accesibilidad emulan cada entrada de usuario posible que se realiza en un objeto
TriSwitch
(heredado deView
). - Eventos de accesibilidad: Informan a los servicios de accesibilidad sobre todas las formas en que las que puede cambiar la apariencia de un objeto
TriSwitch
cuando la pantalla se vuelve a cargar o se actualiza (heredado deView
). - Características: Son detalles sobre cada objeto
TriSwitch
, como el contenido de cualquier texto que muestra (heredado deTextView
). - Información de estado: Es la descripción del estado de un objeto
TriSwitch
en un determinado momento, como "marcado" o "desmarcado" (heredado deCompoundButton
). - Descripción de texto del estado: Es una explicación basada en texto de lo que representa cada estado (heredado de
Switch
).
Este comportamiento agregado, proveniente de Switch
y sus superclases, es prácticamente el comportamiento deseado de los objetos TriSwitch
. Por lo tanto, tu implementación puede enfocarse en expandir la cantidad de estados posibles de 2 a 3.
Define eventos personalizados
Cuando extiendes un widget del sistema, es probable que cambies algún aspecto de la manera en la que los usuarios interactúan con él. Es importante definir estos cambios de interacción para que los servicios de accesibilidad puedan actualizar el widget de tu app como si el usuario interactuara directamente con él.
Como lineamiento general, para cada devolución de llamada basada en vistas que anules, debes volver a definir la acción de accesibilidad correspondiente anulando ViewCompat.replaceAccessibilityAction()
.
Durante las pruebas de la app, puedes llamar a ViewCompat.performAccessibilityAction()
para validar el comportamiento de estas acciones redefinidas.
Cómo funcionaría este principio para los objetos TriSwitch
A diferencia de un objeto Switch
común, presionar un objeto TriSwitch
cambia entre 3 estados posibles. Por lo tanto, la acción de accesibilidad ACTION_CLICK
correspondiente debe actualizarse:
Kotlin
class TriSwitch(context: Context) : Switch(context) { // 0, 1, or 2. var currentState: Int = 0 private set init { updateAccessibilityActions() } private fun updateAccessibilityActions() { ViewCompat.replaceAccessibilityAction(this, ACTION_CLICK, action-label) { view, args -> moveToNextState() }) } private fun moveToNextState() { currentState = (currentState + 1) % 3 } }
Java
public class TriSwitch extends Switch { // 0, 1, or 2. private int currentState; public int getCurrentState() { return currentState; } public TriSwitch() { updateAccessibilityActions(); } private void updateAccessibilityActions() { ViewCompat.replaceAccessibilityAction(this, ACTION_CLICK, action-label, (view, args) -> moveToNextState()); } private void moveToNextState() { currentState = (currentState + 1) % 3; } }
Utiliza señales que no hagan uso del color
A fin de ayudar a los usuarios daltónicos, utiliza señales que no requieran el uso del color para distinguir elementos de la IU dentro de las pantallas de tu app. Algunas de estas técnicas consisten en usar diferentes formas o tamaños, mostrar patrones visuales o de texto, o agregar respuesta táctil o de audio para identificar las diferencias entre los elementos.
En la figura 1, se muestran dos versiones de una actividad. Una versión solo usa color para distinguir entre dos acciones posibles en un flujo de trabajo. La otra versión usa la práctica recomendada de incluir formas y texto además de color para destacar las diferencias entre las dos opciones:
Mejora la accesibilidad del contenido multimedia
Si estás desarrollando una app que incluye contenido multimedia, como un clip de video o una grabación de audio, asegúrate de que los usuarios con diferentes tipos de necesidades de accesibilidad puedan comprender el material. En particular, te recomendamos que hagas lo siguiente:
- Incluye controles que les permitan a los usuarios pausar o detener el contenido multimedia, cambiar el volumen y activar o desactivar los subtítulos.
- Si en un video se presenta información fundamental para completar un flujo de trabajo, proporciona el mismo contenido en un formato alternativo, como una transcripción.
Recursos adicionales
Si deseas obtener más información sobre cómo mejorar la accesibilidad de tu app, consulta los siguientes recursos adicionales: