Además de la información principal que lleva una función de componibilidad, como una cadena de texto de una función de componibilidad Text, puede ser útil tener más información complementaria sobre los elementos de la IU.
La información sobre el significado y la función de un componente en Compose se denomina semántica, que es una forma de proporcionar contexto adicional sobre las funciones de componibilidad a servicios como la accesibilidad, el autocompletado y las pruebas. Por ejemplo, un ícono de cámara puede ser visualmente solo una imagen, pero el significado semántico podría ser "Tomar una foto".
Si combinas la semántica adecuada con las APIs de Compose apropiadas, proporcionas la mayor cantidad de información posible sobre tu componente a los servicios de accesibilidad, que luego deciden cómo representarla para el usuario.
Las APIs de Material, Compose UI y Foundation incluyen semántica integrada que sigue su rol y función específicos, pero también puedes modificar esta semántica para las APIs existentes o establecer otras nuevas para los componentes personalizados, según tus requisitos específicos.
Propiedades semánticas
Las propiedades semánticas transmiten el significado del elemento que admite composición correspondiente. Por
ejemplo, la función de componibilidad Text contiene una propiedad semántica text, porque
ese es el significado de esa función de componibilidad. Un Icon contiene una propiedad contentDescription (si la establece el desarrollador) que transmite en texto el significado del ícono.
Considerar cómo las propiedades semánticas transmiten el significado de una función de componibilidad. Considera un
Switch. El usuario lo verá de la siguiente manera:
Switch en sus estados "Activado" y "Desactivado"Para describir el significado de este elemento, podrías decir lo siguiente: "Este es un interruptor, que es un elemento que se puede activar o desactivar, y se encuentra en el estado 'Activado'. Puedes hacer clic en él para interactuar con él".
Las propiedades semánticas se usan exactamente para este fin. El nodo de semántica de este elemento Switch contiene las siguientes propiedades, como se visualiza con el Inspector de diseño:
Switch que admite composición.El Role indica el tipo de elemento. El StateDescription describe cómo
se debe hacer referencia al estado "Activado". De forma predeterminada, esta es una versión localizada de la palabra "Activado", pero se puede hacer más específica (por ejemplo, "Habilitado") según el contexto. El ToggleableState es el estado actual del interruptor. La propiedad OnClick hace referencia al método que se usa para interactuar con este elemento.
Hacer un seguimiento de las propiedades semánticas de cada elemento componible en tu app desbloquea muchas posibilidades potentes:
- Los servicios de accesibilidad usan las propiedades para representar la IU que se muestra en la pantalla y permitir que los usuarios interactúen con ella. Para el elemento Switch componible, TalkBack podría anunciar: "Activado; Switch; presiona dos veces para activar o desactivar". El usuario puede presionar dos veces la pantalla para desactivar el interruptor.
-
El framework de pruebas usa las propiedades para encontrar nodos, interactuar con ellos y realizar aserciones:
val mySwitch = SemanticsMatcher.expectValue( SemanticsProperties.Role, Role.Switch ) composeTestRule.onNode(mySwitch) .performClick() .assertIsOff()
Los elementos componibles y los modificadores que se compilan sobre la biblioteca de base de Compose ya establecen las propiedades relevantes de forma predeterminada. De manera opcional, puedes cambiar estas propiedades de forma manual para mejorar la compatibilidad con la accesibilidad en casos de uso específicos o cambiar la estrategia de combinación o eliminación de tus elementos de componibilidad.
Para indicar el tipo de contenido específico de tu componente a los servicios de accesibilidad, puedes aplicar una variedad de semánticas diferentes. Estas adiciones respaldarán la información semántica principal en su lugar y ayudarán a los servicios de accesibilidad a ajustar cómo se representa, anuncia o interactúa con tu componente.
Para obtener una lista completa de las propiedades de semántica, consulta el objeto SemanticsProperties. Para obtener una lista completa de las posibles acciones de accesibilidad, consulta el objeto SemanticsActions.
Encabezados
Las apps suelen contener pantallas con contenido enriquecido, como artículos largos o páginas de noticias, que suelen dividirse en diferentes subsecciones con encabezados:
Los usuarios con necesidades de accesibilidad pueden tener dificultades para navegar por una pantalla de este tipo con facilidad. Para mejorar la experiencia de navegación, algunos servicios de accesibilidad permiten
navegar con mayor facilidad directamente entre secciones o encabezados. Para habilitar esta opción, indica que tu componente es un heading definiendo su propiedad semántica:
@Composable private fun Subsection(text: String) { Text( text = text, style = MaterialTheme.typography.headlineSmall, modifier = Modifier.semantics { heading() } ) }
Alertas y ventanas emergentes
Si tu componente es una alerta o una ventana emergente, como un Snackbar, es posible que quieras indicarles a los servicios de accesibilidad que se puede transmitir a los usuarios una nueva estructura o actualizaciones del contenido.
Los componentes similares a alertas se pueden marcar con la propiedad de semántica liveRegion. Esto permite que los servicios de accesibilidad notifiquen automáticamente al usuario sobre los cambios en este componente o sus elementos secundarios:
PopupAlert( message = "You have a new message", modifier = Modifier.semantics { liveRegion = LiveRegionMode.Polite } )
Debes usar liveRegionMode.Polite en la mayoría de los casos en los que la atención de los usuarios solo debe dirigirse brevemente a las alertas o al contenido importante que cambia en la pantalla.
Debes usar liveRegion.Assertive con moderación para evitar comentarios disruptivos.
Se debe usar en situaciones en las que es fundamental que los usuarios conozcan el contenido urgente:
PopupAlert( message = "Emergency alert incoming", modifier = Modifier.semantics { liveRegion = LiveRegionMode.Assertive } )
Las regiones live no se deben usar en contenido que se actualiza con frecuencia, como temporizadores de cuenta regresiva, para evitar abrumar a los usuarios con comentarios constantes.
Componentes similares a ventanas
Los componentes personalizados similares a ventanas, como ModalBottomSheet, necesitan indicadores adicionales para diferenciarlos del contenido circundante. Para ello, puedes usar la semántica paneTitle, de modo que los servicios de accesibilidad puedan representar de forma adecuada cualquier cambio relevante en la ventana o el panel, junto con su información semántica principal:
ShareSheet( message = "Choose how to share this photo", modifier = Modifier .fillMaxWidth() .align(Alignment.TopCenter) .semantics { paneTitle = "New bottom sheet" } )
Como referencia, consulta cómo Material 3 usa paneTitle para sus componentes.
Componentes de error
Para otros tipos de contenido, como los componentes similares a errores, es posible que desees expandir la información semántica principal para los usuarios con necesidades de accesibilidad.
Cuando definas los estados de error, puedes informar a los servicios de accesibilidad sobre su semántica error y proporcionar mensajes de error expandidos.
En este ejemplo, TalkBack lee la información principal del texto de error, seguida de mensajes adicionales expandidos:
Error( errorText = "Fields cannot be empty", modifier = Modifier .semantics { error("Please add both email and password") } )
Componentes de seguimiento del progreso
En el caso de los componentes personalizados que hacen un seguimiento del progreso, es posible que quieras notificar a los usuarios sobre los cambios en el progreso, incluido el valor actual, su rango y el tamaño del paso. Puedes hacerlo con la semántica progressBarRangeInfo, que garantiza que los servicios de accesibilidad estén al tanto de los cambios en el progreso y puedan actualizar a los usuarios según corresponda. Las diferentes tecnologías de accesibilidad también pueden tener formas únicas
de sugerir un aumento o una disminución de la progresión.
ProgressInfoBar( modifier = Modifier .semantics { progressBarRangeInfo = ProgressBarRangeInfo( current = progress, range = 0F..1F ) } )
Información de la lista y los elementos
En las listas y cuadrículas personalizadas con muchos elementos, puede ser útil que los servicios de accesibilidad también reciban información más detallada, como la cantidad total de elementos y los índices.
Si usas la semántica de collectionInfo y collectionItemInfo en la lista y los elementos, respectivamente, en esta lista larga, los servicios de accesibilidad pueden informar a los usuarios en qué índice de elementos se encuentran de la colección total, además de la información semántica textual:
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) } ) } }
Descripción del estado
Un elemento componible puede definir un stateDescription para la semántica que usa el framework de Android para leer el estado en el que se encuentra el elemento componible. Por ejemplo, un elemento componible que se puede activar o desactivar puede estar en un estado "marcado" o "sin marcar". En algunos casos, es posible que quieras anular las etiquetas de descripción de estado predeterminadas que usa Compose. Para ello, especifica de forma explícita las etiquetas de descripción de estado antes de definir un elemento componible como activable:
@Composable private fun TopicItem(itemTitle: String, selected: Boolean, onToggle: () -> Unit) { val stateSubscribed = stringResource(R.string.subscribed) val stateNotSubscribed = stringResource(R.string.not_subscribed) Row( modifier = Modifier .semantics { // Set any explicit semantic properties stateDescription = if (selected) stateSubscribed else stateNotSubscribed } .toggleable( value = selected, onValueChange = { onToggle() } ) ) { /* ... */ } }
Acciones personalizadas
Las acciones personalizadas se pueden usar para gestos de pantalla táctil más complejos, como deslizar para descartar o arrastrar y soltar, ya que estos pueden ser difíciles de usar para los usuarios con discapacidades motrices o de otro tipo.
Para que el gesto de deslizar para descartar sea más accesible, puedes vincularlo a una acción personalizada y pasar la acción de descarte y la etiqueta allí:
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() }
Luego, un servicio de accesibilidad como TalkBack destaca el componente y sugiere que hay más acciones disponibles en su menú, lo que representa la acción de deslizar para descartar:
Otro caso de uso de las acciones personalizadas son las listas largas con elementos que tienen más acciones disponibles, ya que puede ser tedioso para los usuarios iterar en cada acción para cada elemento de forma individual:
Para mejorar la experiencia de navegación, que es especialmente útil para las tecnologías de accesibilidad basadas en la interacción, como la Accesibilidad con interruptores o el Acceso por voz, puedes usar acciones personalizadas en el contenedor para mover las acciones fuera del recorrido individual y a un menú de acciones independiente:
ArticleListItemRow( modifier = Modifier .semantics { customActions = listOf( CustomAccessibilityAction( label = "Open article", action = { openArticle() true } ), CustomAccessibilityAction( label = "Add to bookmarks", action = { addToBookmarks() true } ), ) } ) { Article( modifier = Modifier.clearAndSetSemantics { }, onClick = openArticle, ) BookmarkButton( modifier = Modifier.clearAndSetSemantics { }, onClick = addToBookmarks, ) }
En estos casos, asegúrate de borrar de forma manual la semántica de los elementos secundarios originales con el modificador clearAndSetSemantics, ya que los estás moviendo a acciones personalizadas.
Si usamos la Accesibilidad con interruptores como ejemplo, su menú se abre cuando se selecciona el contenedor y se enumeran las acciones anidadas disponibles allí:
Árbol semántico
Una composición describe la IU de tu app y se produce ejecutando elementos componibles. La composición es una estructura de árbol que consta de los elementos componibles que describen tu IU.
Junto a la composición, existe un árbol paralelo, llamado árbol de semántica. Este árbol describe la IU de una manera alternativa que pueden comprender los servicios de accesibilidad y el framework de prueba. Los servicios de accesibilidad usan el árbol para describir la app a los usuarios con una necesidad específica. El framework de pruebas usa el árbol para interactuar con tu app y realizar aserciones sobre ella. El árbol de semántica no contiene la información sobre cómo dibujar tus elementos componibles, pero contiene información sobre el significado semántico de tus elementos componibles.

Si la app se conforma de elementos que admiten composición y modificadores de la biblioteca base y Material de Compose, el árbol semántico se completará y generará automáticamente. Sin embargo, cuando agregas elementos de componibilidad personalizados de bajo nivel, debes proporcionar su semántica de forma manual. También, en algunas situaciones, es posible que el árbol no represente de forma correcta o completa el significado de los elementos en la pantalla. En este caso, puedes adaptar el árbol.
Por ejemplo, ten en cuenta este calendario personalizado que admite composición:

En este ejemplo, todo el calendario se implementa como un solo elemento que admite composición de bajo nivel si se usa el objeto Layout que admite composición y se dibuja directamente en Canvas.
Si no realizas ninguna otra acción, los servicios de accesibilidad no recibirán suficiente información sobre el contenido del elemento componible ni la selección del usuario en el calendario. Por ejemplo, si un usuario hace clic en el día que contiene 17, el marco de trabajo de accesibilidad solamente recibe la información de descripción de todo el control de calendario. En este caso, el servicio de accesibilidad de TalkBack solo anunciaría "Calendario" o la variante "Calendario de abril" (solo ligeramente mejor), y el usuario no sabría qué día se seleccionó. Para que este elemento componible sea más accesible, deberás agregar información semántica de forma manual.
Árbol combinado y no combinado
Como se mencionó antes, es posible que cada elemento que admite composición en el árbol de IU no tenga propiedades semánticas establecidas o que sí las tenga. Cuando un elemento componible no tiene propiedades semánticas establecidas, no se incluye como parte del árbol de semántica. De esa manera, el árbol semántico solamente incluye los nodos que, en realidad, tienen significado semántico. Sin embargo, con frecuencia, para transmitir el significado correcto de lo que se muestra en la pantalla, también es útil combinar subárboles determinados de nodos y tratarlos como uno solo. De esa manera, puedes razonar sobre un conjunto de nodos como un todo, en lugar de tratar con cada nodo descendiente de forma individual. Como regla general, cada nodo de este árbol representa un elemento enfocable cuando se usan los servicios de accesibilidad.
Un ejemplo de este tipo de elemento que admite composición es Button. Puedes pensar en un botón como un solo elemento, aunque puede contener varios nodos secundarios:
Button(onClick = { /*TODO*/ }) { Icon( imageVector = Icons.Filled.Favorite, contentDescription = null ) Spacer(Modifier.size(ButtonDefaults.IconSpacing)) Text("Like") }
En el árbol de semántica, se combinan las propiedades de los descendientes del botón, y este se presenta como un solo nodo de hoja en el árbol:
Los elementos que admiten composición y los modificadores pueden indicar que quieren combinar las propiedades semánticas de sus elementos subordinados mediante una llamada a Modifier.semantics
(mergeDescendants = true) {}. Establecer esta propiedad en true indica que se deben combinar las propiedades semánticas. En el ejemplo de Button, el elemento componible Button usa el modificador clickable de forma interna, que incluye este modificador semantics. Por lo tanto, se combinan los nodos descendientes del botón.
Lee la documentación de accesibilidad para obtener más información sobre cuándo debes cambiar el comportamiento de combinación en tu elemento que admite composición.
Varios modificadores y elementos que admiten composición en las bibliotecas base y material de Compose tienen esta propiedad establecida. Por ejemplo, los modificadores clickable y toggleable combinarán automáticamente sus elementos subordinados. El elemento ListItem que admite composición también los combinará.
Inspecciona el árbol
De hecho, el árbol semántico consta de dos árboles diferentes. Hay un árbol de Semantics combinado, que combina nodos descendientes cuando mergeDescendants se establece en true.
También hay un árbol de Semantics sin combinar, que no aplica la combinación, sino que mantiene intacto cada nodo. Los servicios de accesibilidad usan el árbol sin combinar y aplican sus propios algoritmos de combinación, teniendo en cuenta la propiedad mergeDescendants. El framework de pruebas usa el árbol combinado de forma predeterminada.
Puedes inspeccionar ambos árboles con el método printToLog(). De forma predeterminada, y como en
los ejemplos anteriores, se registra el árbol combinado. Para imprimir el árbol sin combinar, establece el parámetro useUnmergedTree del comparador onRoot() en true:
composeTestRule.onRoot(useUnmergedTree = true).printToLog("MY TAG")
El Inspector de diseño te permite mostrar el árbol de Semantics combinado y el no combinado. Para ello, selecciona el que prefieras en el filtro de vista:
Para cada nodo del árbol, el Inspector de diseño muestra la semántica combinada y la que se establece en ese nodo en el panel de propiedades:
De forma predeterminada, los comparadores en el marco de trabajo de prueba usan el árbol semántico combinado.
Por eso, puedes interactuar con un Button haciendo coincidir el texto que se muestra dentro de él:
composeTestRule.onNodeWithText("Like").performClick()
Anula este comportamiento configurando el parámetro useUnmergedTree de los comparadores como true, como con el comparador onRoot.
Adapta el árbol
Como se mencionó antes, puedes anular o borrar ciertas propiedades de semántica o cambiar el comportamiento de combinación del árbol. Esto es particularmente relevante cuando creas tus propios componentes personalizados. Si no configuras las propiedades y el comportamiento de combinación correctos, es posible que no se pueda acceder a tu app y que las pruebas se comporten de manera diferente a la esperada. Si quieres obtener más información sobre las pruebas, consulta la guía de pruebas.
Recomendaciones para ti
- Nota: El texto del vínculo se muestra cuando JavaScript está desactivado
- Accesibilidad en Compose
- Material Design 2 en Compose
- Cómo probar tu diseño de Compose