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.
- Cómo usar las funciones de accesibilidad integradas
- Compose ofrece muchos comportamientos de accesibilidad de forma predeterminada. Aprovecha los comportamientos de accesibilidad predefinidos para que tus componentes sean accesibles con poco o ningún trabajo adicional. Compose también proporciona formas de admitir requisitos de accesibilidad más específicos que no se incluyen en las funciones predeterminadas.
- 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 la semántica de un elemento específico, es decir, su significado y propósito. Los lectores de pantalla, como TalkBack, pueden leerles estas etiquetas a los usuarios.
En la mayoría de los casos, las APIs de Compose y Material tienen compatibilidad de accesibilidad predeterminada. Sin embargo, si necesitas especificar manualmente las propiedades semánticas de un elemento de la IU, usa el modificador semantics y la propiedad contentDescription. Para obtener más información sobre la semántica, consulta Semántica.
En las siguientes secciones, se describen otras técnicas de etiquetado.
Elementos editables
Cuando etiquetas elementos editables, como campos de texto, 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 texto de marcador de posición, también llamado texto de sugerencia.
En el siguiente ejemplo, el TextField tiene un parámetro placeholder que proporciona texto de sugerencia.
val usernameState = rememberTextFieldState() TextField( state = usernameState, lineLimits = TextFieldLineLimits.SingleLine, placeholder = { Text("Enter Username") } )
También es común que un campo de texto tenga una etiqueta descriptiva correspondiente que describa lo que los usuarios deben ingresar como entrada.
En el siguiente ejemplo, el objeto TextField tiene un parámetro label que proporciona una descripción de accesibilidad.
TextField( state = rememberTextFieldState(initialText = "Hello"), label = { Text("Label") } )
Para obtener más información sobre el texto y la entrada del usuario, consulta Cómo configurar campos de texto.
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.
Por ejemplo, cuando tienes un LazyColumn o un LazyRow, usa el modificador semantics para asignar un collectionItemInfo único a cada elemento, como se muestra en el siguiente fragmento:
MilkyWayList( modifier = Modifier .semantics { collectionInfo = CollectionInfo( rowCount = milkyWay.count(), columnCount = 1 ) } ) { milkyWay.forEachIndexed { index, text -> Text( text = text, modifier = Modifier.semantics { collectionItemInfo = CollectionItemInfo(index, 0, 0, 0) } ) } }
Para obtener más información sobre las propiedades semánticas de las listas y las cuadrículas, consulta Información de listas y elementos.
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 principal (como Column, Row o Box). Usa el modificador semantics del contenedor principal para establecer mergeDescendants en true.
De esta manera, los servicios de accesibilidad pueden presentar las descripciones de contenido de los elementos internos, una tras otra, en un único anuncio. La 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.
En el siguiente fragmento, el elemento Row componible actúa como el contenedor principal.
Dentro de Row, hay elementos relacionados que muestran metadatos de una entrada de blog: el avatar del autor, su nombre y el tiempo de lectura estimado.
Si se configura mergeDescendants como true, se agrupan estos elementos internos para que los servicios de accesibilidad puedan tratarlos como una sola unidad.
@Composable private fun PostMetadata(metadata: Metadata) { // Merge elements below for accessibility purposes Row(modifier = Modifier.semantics(mergeDescendants = true) {}) { Image( imageVector = Icons.Filled.AccountCircle, contentDescription = null // decorative ) Column { Text(metadata.author.name) Text("${metadata.date} • ${metadata.readTimeMinutes} min read") } } }
Cuando agrupes elementos relacionados, como en el ejemplo anterior, haz que solo el contenedor principal sea interactivo. Evita agregar modificadores clickable o focusable a los elementos secundarios internos. En su lugar, aplica los modificadores al elemento principal Row o Column.
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, cuando crees una descripción de contenido para un grupo, evita agregar el texto de sus elementos secundarios. Si lo haces, la descripción del grupo se vuelve frágil y, cuando cambia el texto de un elemento secundario, es posible que la descripción del grupo ya no coincida con el texto visible.
En el contexto de una lista o una cuadrícula, es posible que un lector de pantalla consolide el texto de los nodos de texto secundarios de un elemento de lista o cuadrícula. Se recomienda no modificar este anuncio.
Para obtener más información sobre la combinación de semántica, consulta Combinación y borrado.
Encabezados dentro de texto
Algunas apps usan encabezados para resumir grupos de texto que se muestran en la pantalla. Si un elemento específico representa un encabezado, puedes indicar su objetivo para los servicios de accesibilidad estableciendo la propiedad heading en el modificador semantics.
@Composable private fun Subsection(text: String) { Text( text = text, style = MaterialTheme.typography.headlineSmall, modifier = Modifier.semantics { heading() } ) }
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.
Para obtener más información sobre la propiedad semántica heading, consulta Encabezados.
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.
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.
ShareSheet( message = "Choose how to share this photo", modifier = Modifier .fillMaxWidth() .align(Alignment.TopCenter) .semantics { paneTitle = "New bottom sheet" } )
Para obtener más información sobre la propiedad semántica paneTitle, consulta Componentes similares a ventanas.
Elementos decorativos
Si un elemento de tu IU solo existe para brindar espacio visual o mejorar la apariencia, establece las propiedades adecuadas en el elemento para indicar que los servicios de accesibilidad pueden ignorarlo.
Para los elementos Image o Icon componibles, establece contentDescription = null. Para otros elementos puramente decorativos que no proporcionan contexto ni funcionalidad, puedes usar hideFromAccessibility. Esta propiedad de semántica indica a los servicios de accesibilidad que ignoren el elemento.
Si un elemento componible interactivo contiene elementos secundarios decorativos no interactivos, usa clearAndSetSemantics para asegurarte de que los servicios de accesibilidad no los recorran. Ten en cuenta que clearAndSetSemantics borra por completo la semántica predeterminada de un elemento y sus elementos secundarios. Esto te permite definir un nuevo elemento de accesibilidad unificado. Por lo general, se usa este enfoque para componentes personalizados complejos.
En el siguiente ejemplo, Icon y Text son elementos secundarios decorativos dentro de un botón de activación personalizado. Para evitar que los servicios de accesibilidad recorran estos elementos secundarios de forma individual, puedes borrar su semántica con clearAndSetSemantics en el elemento Row principal. Esto indica a los servicios de accesibilidad que traten todo el Row como un botón de activación que se puede recorrer:
// Developer might intend this to be a toggleable. // Using `clearAndSetSemantics`, on the Row, a clickable modifier is applied, // a custom description is set, and a Role is applied. @Composable fun FavoriteToggle() { val checked = remember { mutableStateOf(true) } Row( modifier = Modifier .toggleable( value = checked.value, onValueChange = { checked.value = it } ) .clearAndSetSemantics { stateDescription = if (checked.value) "Favorited" else "Not favorited" toggleableState = ToggleableState(checked.value) role = Role.Switch }, ) { Icon( imageVector = Icons.Default.Favorite, contentDescription = null // not needed here ) Text("Favorite?") } }
Para obtener más información sobre cómo borrar la semántica, consulta Cómo borrar y establecer la semántica.
Agrega acciones de accesibilidad
Es importante asegurarse de que los usuarios de servicios de accesibilidad tengan una forma de completar todos los flujos de usuarios en tu app.
Si la interacción de tu elemento componible personalizado cambia el estado de la app de una manera que no es obvia, proporciona etiquetas descriptivas para las acciones de toque estándar con parámetros como onClickLabel o onLongClickLabel en Modifier.clickable o Modifier.combinedClickable.
Para interacciones complejas que no se pueden asignar a toques estándar, usa customActions.
Por ejemplo, si tu app permite que los usuarios arrastren un elemento a otra ubicación o deslicen un elemento en una lista, puedes proporcionar una forma alternativa de completar estos flujos de usuarios exponiendo la acción a los servicios de accesibilidad. De esta manera, los usuarios de TalkBack, Acceso por voz o Accesibilidad con interruptores pueden realizar acciones que, de otro modo, solo estarían disponibles a través de gestos.
En Compose, puedes definir acciones de accesibilidad personalizadas a través de la propiedad customActions en el modificador semantics, con CustomAccessibilityAction.
Por ejemplo, si tu app les permite a los usuarios deslizar un elemento para descartarlo, puedes exponer la funcionalidad a través de una acción de accesibilidad personalizada:
SwipeToDismissBox( modifier = Modifier.semantics { // Represents the swipe to dismiss for accessibility customActions = listOf( CustomAccessibilityAction( label = "Remove article from list", action = { removeArticle() true } ) ) }, state = rememberSwipeToDismissBoxState(), backgroundContent = {} ) { ArticleListItem() }
Con la acción de accesibilidad personalizada implementada, los usuarios pueden acceder a la acción a través del menú de acciones.
Para obtener más información sobre las acciones personalizadas, consulta Acciones personalizadas.
Haz que resulte fácil comprender las acciones disponibles
Cuando un elemento de la IU admite acciones como mantener presionado, un servicio de accesibilidad, como TalkBack, lo anuncia como "Mantén presionado para realizar una presión prolongada".
Este anuncio genérico no le brinda al usuario ningún contexto sobre lo que hace una acción de mantener presionado.
Para que este anuncio sea más útil, especifica una descripción significativa para la acción.
En Compose, los modificadores de interacción estándar, como clickable y combinedClickable, tienen parámetros integrados (es decir, onClickLabel y onLongClickLabel) que puedes usar para proporcionar descripciones de las acciones, como en el siguiente ejemplo:
var contextMenuPhotoId by rememberSaveable { mutableStateOf<Int?>(null) } val haptics = LocalHapticFeedback.current LazyVerticalGrid(columns = GridCells.Adaptive(minSize = 128.dp)) { items(photos, { it.id }) { photo -> ImageItem( photo, Modifier .combinedClickable( onClick = { activePhotoId = photo.id }, onLongClick = { haptics.performHapticFeedback(HapticFeedbackType.LongPress) contextMenuPhotoId = photo.id }, onLongClickLabel = stringResource(R.string.open_context_menu) ) ) } } if (contextMenuPhotoId != null) { PhotoActionsSheet( photo = photos.first { it.id == contextMenuPhotoId }, onDismissSheet = { contextMenuPhotoId = null } ) }
Esto hace que TalkBack anuncie "Abrir menú contextual", lo que ayuda a los usuarios a comprender el propósito de la acción.
También puedes especificar una etiqueta directamente en el modificador semantics.
Para obtener más información sobre cómo responder a los toques y clics, consulta Tocar y presionar y Elementos interactivos.
Usa las funciones de accesibilidad integradas
Cuando diseñes la IU de tu app, aprovecha las funciones de accesibilidad integradas para evitar volver a implementar la funcionalidad que ya existe. Las APIs de Material, Compose UI y Foundation implementan y ofrecen muchas prácticas accesibles de forma predeterminada.
En Jetpack Compose, usa elementos componibles integrados, como Button, Switch y Checkbox, para crear IU accesibles. Estos componentes vienen preempaquetados con modificadores semantics, como role y stateDescription, que puedes usar para que tus apps sean más accesibles.
Aplica semántica a componentes personalizados
Cuando crees un componente personalizado, ten en cuenta qué tipo de compatibilidad con la accesibilidad requiere este componente para cumplir su función. A menudo, las APIs de Compose estándar que ya usas, como clickable, toggleable o selectable, son suficientes porque propagan automáticamente el árbol semántico por ti.
Sin embargo, algunos componentes requieren información más específica de la que proporcionan los modificadores estándar. En estos casos, busca modificadores especializados (como triStateToggleable) o, si no existen, proporciona semántica de forma explícita con Modifier.semantics de bajo nivel.
Por ejemplo, considera un TriStateSwitch, un interruptor con tres estados (activado, desactivado y desconocido).
Si bien un modificador toggleable estándar supone dos estados, el modificador triStateToggleable controla la complejidad del tercer estado. Establece automáticamente los atributos de accesibilidad Role (Switch) y State. De esta manera, los servicios de accesibilidad reciben información precisa y no es necesario que definas la semántica de forma manual.
En el siguiente fragmento de código, se muestra un TriStateSwitch que usa este enfoque:
@Composable fun TriStateSwitch( state: ToggleableState, onClick: () -> Unit, modifier: Modifier = Modifier ) { // A real implementation would include custom drawing for the switch. // This example uses a Box to demonstrate the semantics. Box( modifier = modifier .size(width = 64.dp, height = 40.dp) // triStateToggleable handles the semantics (Role and State) // automatically, so explicit Modifier.semantics is not needed here. .triStateToggleable( state = state, onClick = onClick, role = Role.Switch ) // Add visual feedback based on the state .background( when (state) { ToggleableState.On -> Color.Green ToggleableState.Off -> Color.Gray ToggleableState.Indeterminate -> Color.Yellow } ) ) } // Usage within another composable: var state by remember { mutableStateOf(ToggleableState.Off) } TriStateSwitch( state = state, onClick = { state = when (state) { ToggleableState.Off -> ToggleableState.Indeterminate ToggleableState.Indeterminate -> ToggleableState.On ToggleableState.On -> ToggleableState.Off } } )
Cuando compiles un componente personalizado, asegúrate de proporcionar todas las propiedades semánticas pertinentes para fines de accesibilidad. Por ejemplo, si tu componente imita un control estándar, como un interruptor o un botón, estas propiedades incluyen el rol del componente (como Role.Switch o Role.Button), stateDescription (como "Activado", "Desactivado", "Marcado" o "No marcado") y cualquier etiqueta de acción pertinente. Para obtener más información, consulta Componentes personalizados.
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, intenta hacer 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 para mejorar la accesibilidad de tu app, consulta los siguientes recursos adicionales: