A medida que los servicios de accesibilidad navegan por los elementos de la pantalla, es importante que estos elementos se agrupen, se separen o incluso se oculten con el nivel de detalle correcto. Cuando todos los elementos componibles de bajo nivel de la pantalla se destacan de forma independiente, los usuarios tienen que interactuar mucho para moverse por toda la pantalla. Si los elementos se combinan de manera demasiado agresiva, es posible que los usuarios no comprendan qué elementos pertenecen a ellos. Si hay elementos en la pantalla que son puramente decorativos, estos se pueden ocultar de los servicios de accesibilidad. En estos casos, puedes usar las APIs de Compose para combinar, borrar y ocultar la semántica.
Semántica de combinación
Cuando aplicas un modificador clickable
a un elemento componible superior, Compose fusiona automáticamente todos los elementos secundarios debajo de él. Para comprender cómo los componentes interactivos de Material y Foundation de Compose usan estrategias de combinación de forma predeterminada, consulta la sección Elementos interactivos.
Es común que un componente conste de varios elementos componibles. Estos elementos componibles podrían formar un grupo lógico y cada uno podría contener información importante, pero es posible que desees que los servicios de accesibilidad los vean como un solo elemento.
Por ejemplo, piensa en un elemento componible que muestre el avatar de un usuario, su nombre y algunos datos adicionales:

Puedes habilitar Compose para que combine estos elementos mediante el parámetro mergeDescendants
en el modificador de semántica. De esta manera, los servicios de accesibilidad tratan el componente como una entidad, y se combinan todas las propiedades semánticas de los elementos subordinados:
@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") } } }
Los servicios de accesibilidad ahora se enfocan en todo el contenedor de una vez y combinan su contenido:

Cada propiedad semántica tiene una estrategia de combinación definida. Por ejemplo, la propiedad ContentDescription
agrega todos los valores de ContentDescription
subordinados a una lista. Puedes comprobar la estrategia de combinación de una propiedad semántica si verificas su implementación mergePolicy
en SemanticsProperties.kt.
Las propiedades pueden adoptar el valor superior o el secundario, combinar los valores en una lista o una cadena, no permitir la combinación en absoluto y, en su lugar, arrojar una excepción, o cualquier otra estrategia de combinación personalizada.
Hay otras situaciones en las que esperas que la semántica de los elementos secundarios se combine en una superior, pero eso no sucede. En el siguiente ejemplo, tenemos un elemento superior de la lista clickable
con elementos secundarios, y podríamos esperar que el elemento superior los combine a todos:

@Composable private fun ArticleListItem( openArticle: () -> Unit, addToBookmarks: () -> Unit, ) { Row(modifier = Modifier.clickable { openArticle() }) { // Merges with parent clickable: Icon( painter = painterResource(R.drawable.ic_logo), contentDescription = "Article thumbnail" ) ArticleDetails() // Defies the merge due to its own clickable: BookmarkButton(onClick = addToBookmarks) } }
Cuando el usuario presiona el elemento clickable
Row
, se abre el artículo. Dentro, hay un BookmarkButton
para agregar el artículo a favoritos. Este botón anidado aparece como no fusionado, mientras que el resto del contenido secundario dentro de la fila está fusionado:

Row
. El árbol separado incluye nodos separados para cada elemento Text
componible.Por diseño, algunos elementos componibles no se combinan automáticamente en un elemento superior. Un elemento superior no puede combinar sus elementos secundarios cuando estos también se combinan, ya sea desde la configuración de mergeDescendants = true
de forma explícita o a través de componentes que se combinan, como botones o elementos en los que se puede hacer clic. Saber cómo se combinan o se resisten a la combinación ciertas APIs puede ayudarte a depurar algunos comportamientos potencialmente inesperados.
Usa la combinación cuando los elementos secundarios constituyan un grupo lógico y sensato debajo de su elemento superior. Sin embargo, si los elementos secundarios anidados necesitan un ajuste manual o la eliminación de su propia semántica, es posible que otras APIs se adapten mejor a tus necesidades (por ejemplo, clearAndSetSemantics
).
Borra y establece semántica
Si la información semántica debe borrarse o reemplazarse por completo, una API potente para usar es clearAndSetSemantics
.
Cuando un componente necesita que se borren su propia semántica y la de sus descendientes, usa esta API con una lambda vacía. Cuando se deban reemplazar sus semánticas, incluye tu contenido nuevo dentro de la lambda.
Ten en cuenta que, cuando se borra con una lambda vacía, las semánticas borradas no se envían a ningún consumidor que use esta información, como la accesibilidad, el autocompletado o las pruebas. Cuando se reemplaza el contenido con clearAndSetSemantics{/*semantic information*/}
, la semántica nueva reemplaza toda la semántica anterior del elemento y sus subordinados.
El siguiente es un ejemplo de un componente de activación personalizado, representado por una fila interactiva con un ícono y texto:
// 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?") } }
Aunque el ícono y el texto tienen cierta información semántica, juntos no indican que este componente sea activable. La combinación no es suficiente, ya que debes proporcionar información adicional sobre el componente.
Como el fragmento anterior crea un componente de activación personalizado, debes agregar la función de activación, así como las semánticas stateDescription
, toggleableState
y role
. De esta manera, el estado del componente y la acción asociada están disponibles. Por ejemplo, TalkBack anuncia "Presiona dos veces para activar o desactivar" en lugar de "Presiona dos veces para activar".
Si borras la semántica original y configuras una nueva y más descriptiva, los servicios de accesibilidad ahora pueden ver que este es un componente que se puede activar o desactivar y que puede alternar el estado.
Cuando uses clearAndSetSemantics
, ten en cuenta lo siguiente:
- Como los servicios no reciben información cuando se configura esta API, es mejor usarla con moderación.
- Los agentes de IA y los servicios similares pueden usar la información semántica para comprender la pantalla, por lo que solo se debe borrar cuando sea necesario.
- Se pueden establecer semánticas personalizadas dentro de la expresión lambda de la API.
- El orden de los modificadores es importante: esta API borra toda la semántica que se encuentra después del lugar en el que se aplica, independientemente de otras estrategias de combinación.
Oculta la semántica
En algunos casos, no es necesario enviar elementos a los servicios de accesibilidad. Es posible que su información adicional sea redundante para la accesibilidad o que sea puramente decorativa y no interactiva. En estos casos, puedes ocultar elementos con la API de hideFromAccessibility
.
En los siguientes ejemplos, se muestran componentes que podrían ser necesarios ocultar: una marca de agua redundante que abarca un componente y un carácter que se usa para separar la información de forma decorativa.
@Composable fun WatermarkExample( watermarkText: String, content: @Composable () -> Unit, ) { Box { WatermarkedContent() // Mark the watermark as hidden to accessibility services. WatermarkText( text = watermarkText, color = Color.Gray.copy(alpha = 0.5f), modifier = Modifier .align(Alignment.BottomEnd) .semantics { hideFromAccessibility() } ) } } @Composable fun DecorativeExample() { Text( modifier = Modifier.semantics { hideFromAccessibility() }, text = "A dot character that is used to decoratively separate information, like •" ) }
El uso de hideFromAccessibility
aquí garantiza que la marca de agua y la decoración se oculten de los servicios de accesibilidad, pero aún conservan su semántica para otros casos de uso, como las pruebas.
Desglose de los casos de uso
A continuación, se incluye un resumen de casos de uso para comprender cómo diferenciar claramente entre las APIs anteriores:
- Cuando el contenido no está diseñado para que lo usen los servicios de accesibilidad, haz lo siguiente:
- Usa
hideFromAccessibility
cuando el contenido sea posiblemente decorativo o redundante, pero aún debas probarlo. - Usa
clearAndSetSemantics{}
con una lambda vacía cuando se deban borrar las semánticas de elementos superiores y secundarios para todos los servicios. - Usa
clearAndSetSemantics{/*content*/}
con contenido dentro de la expresión lambda cuando se deba configurar manualmente la semántica de un componente.
- Usa
- Cuando el contenido debe tratarse como una entidad y necesita que toda la información de sus elementos secundarios esté completa, haz lo siguiente:
- Usa la combinación de descendientes semánticos.

Recomendaciones para ti
- Nota: El texto del vínculo se muestra cuando JavaScript está desactivado
- Accesibilidad en Compose
- [Material Design 2 en Compose][19]
- Cómo probar tu diseño de Compose