Para brindar asistencia a usuarios con necesidades de accesibilidad, el framework de Android te permite crear un servicio de accesibilidad capaz de presentar contenido de apps a los usuarios y de operarlas por ellos.
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 con interruptores: 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 usando solo uno o dos 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 incluidos en Cómo mejorar la accesibilidad de las apps.
Cada una de estas prácticas recomendadas, que se describen en las siguientes secciones, pueden 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.
- Agrega acciones de accesibilidad
- Cuando agregas acciones de accesibilidad, les permites a los usuarios de esos servicios completar flujos críticos en tu app.
- Extiende los 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 para que los usuarios que lo consuman no tengan que depender por completo de señales visuales o sonoras.
Etiqueta los 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.
En la mayoría de los casos, debes especificar la descripción de un elemento de la IU en el archivo de recursos de diseño que lo contiene. 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 se describen en las siguientes secciones.
Elementos editables
Cuando etiquetas elementos editables, como objetos EditText
, resulta útil mostrar texto que brinde un ejemplo de entrada válida 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
. Para obtener más detalles, consulta la siguiente sección.
Pares de elementos en los que uno describe al otro
Es común que un elemento EditText
tenga un objeto View
correspondiente que describa lo que los usuarios deben ingresar en el elemento EditText
. 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 esta 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
, para 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 esta manera, los servicios de accesibilidad pueden presentar las descripciones de contenido de los elementos internos, uno tras el otro, en un único 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.
Nota: En general, deberías evitar crear una descripción de contenido para un grupo agregando el texto de su hijos o hijas. Hacerlo hace que la descripción del grupo se vuelva frágil y cuando el texto de una secundario, es posible que la descripción del grupo ya no coincida con el texto visible.
En un contexto de lista o cuadrícula, un lector de pantalla puede consolidar el texto de una lista o nodos de texto secundarios del elemento de cuadrícula. Conviene evitar modificar este anuncio.
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 (nivel de API 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:importantForAccessibility
en "no"
.
Agrega acciones de accesibilidad
Es importante que le permitas a los usuarios de servicios de accesibilidad realizar todos los flujos de usuarios de tu app. Por ejemplo, si un usuario puede deslizar un elemento de una lista, esta acción también se puede exponer a los servicios de accesibilidad de modo que los usuarios tengan una forma alternativa de completar el mismo flujo.
Haz que todas las acciones resulten accesibles
Un usuario de TalkBack, Acceso por voz o Accesibilidad con interruptores podría necesitar formas alternativas de completar determinados flujos de usuarios dentro de la app. Para acciones asociadas con gestos como el de arrastrar y soltar o los deslizamientos, tu app puede exponer las acciones de modo que resulte accesible para los usuarios de servicios de accesibilidad.
Con las acciones de accesibilidad, la app puede ofrecer a los usuarios maneras alternativas de completar una acción.
Por ejemplo, si tu app les permite a los usuarios deslizar un elemento, también puedes exponer la funcionalidad a través de una acción de accesibilidad personalizada, como esta:
Kotlin
ViewCompat.addAccessibilityAction( // View to add accessibility action itemView, // Label surfaced to user by an accessibility service getText(R.id.archive) ) { _, _ -> // Same method executed when swiping on itemView archiveItem() true }
Java
ViewCompat.addAccessibilityAction( // View to add accessibility action itemView, // Label surfaced to user by an accessibility service getText(R.id.archive), (view, arguments) -> { // Same method executed when swiping on itemView archiveItem(); return true; } );
With the custom accessibility action implemented, users can access the action through the actions menu.
Make available actions understandable
When a view supports actions such as touch & hold, an accessibility service such as TalkBack announces it as "Double tap and hold to long press."
This generic announcement doesn't give the user any context about what a touch & hold action does.
To make this announcement more descriptive, you can replace the accessibility action’s announcement like so:
Kotlin
ViewCompat.replaceAccessibilityAction( // View that contains touch & hold action itemView, AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_LONG_CLICK, // Announcement read by TalkBack to surface this action getText(R.string.favorite), null )
Java
ViewCompat.replaceAccessibilityAction( // View that contains touch & hold action itemView, AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_LONG_CLICK, // Announcement read by TalkBack to surface this action getText(R.string.favorite), null );
This results in TalkBack announcing "Double tap and hold to favorite," helping users understand the purpose of the action.
Extend system widgets
Note: When you design your app's UI, use or extend
system-provided widgets that are as far down Android's class hierarchy as
possible. System-provided widgets that are far down the hierarchy already
have most of the accessibility capabilities your app needs. It's easier
to extend these system-provided widgets than to create your own from the more
generic View
,
ViewCompat
,
Canvas
, and
CanvasCompat
classes.
If you must extend View
or Canvas
directly, which
might be necessary for a highly customized experience or a game level, see
Make custom views more
accessible.
This section uses the example of implementing a special type of
Switch
called TriSwitch
while following
best practices around extending system widgets. A TriSwitch
object works similarly to a Switch
object, except that each instance of
TriSwitch
allows the user to toggle among three possible states.
Extend from far down the class hierarchy
The Switch
object inherits from several framework UI classes in its hierarchy:
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 brinda la mayoría de las funciones de accesibilidad que necesita la clase TriSwitch
:
- Acciones de accesibilidad: Informan al sistema acerca de cómo los servicios de accesibilidad pueden emular cada entrada posible de los usuarios realizada 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 de Switch
y sus superclases es casi el mismo que el de los objetos TriSwitch
. Por lo tanto, tu implementación puede enfocarse en expandir la cantidad de estados posibles de dos a tres.
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 tres 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
Para 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 la app, consulta los siguientes recursos adicionales: