Para ayudar a las personas con necesidades de accesibilidad a usar tu app de forma exitosa, diseña tu app para cumplir con requisitos clave de accesibilidad.
Considera el tamaño mínimo del objetivo táctil
Todos los elementos de la pantalla en los que se puede hacer clic, que se pueden tocar o con los que se puede interactuar deben ser lo suficientemente grandes para permitir una interacción confiable. Cuando dimensiones estos elementos, asegúrate de establece el tamaño mínimo en 48 dp para cumplir con la norma de Material Design lineamientos de accesibilidad.
Los componentes de Material, como Checkbox
, RadioButton
y Switch
,
Slider
y Surface
: establecen este tamaño mínimo internamente, pero solo
cuándo el componente puede recibir acciones del usuario. Por ejemplo, cuando un elemento Checkbox
tiene
el parámetro onCheckedChange
establecido en un valor no nulo, la casilla de verificación incluye
para que el ancho y la altura sean de al menos 48 dp.
@Composable private fun CheckableCheckbox() { Checkbox(checked = true, onCheckedChange = {}) }
Cuando el parámetro onCheckedChange
se establece como nulo, el padding no se
porque no se puede interactuar directamente con él.
@Composable private fun NonClickableCheckbox() { Checkbox(checked = true, onCheckedChange = null) }
Cuando implementes controles de selección, como Switch
, RadioButton
o
Checkbox
, por lo general, elevas el comportamiento de hacer clic a un contenedor superior, establecido
la devolución de llamada de clic en el elemento componible para null
y agrega toggleable
o
selectable
al elemento componible superior.
@Composable private fun CheckableRow() { MaterialTheme { var checked by remember { mutableStateOf(false) } Row( Modifier .toggleable( value = checked, role = Role.Checkbox, onValueChange = { checked = !checked } ) .padding(16.dp) .fillMaxWidth() ) { Text("Option", Modifier.weight(1f)) Checkbox(checked = checked, onCheckedChange = null) } } }
Cuando el tamaño de un elemento componible para hacer clic es menor que el tamaño del objetivo táctil mínimo, Compose aumenta el tamaño del objetivo táctil. Para ello, se expande el tamaño del objetivo táctil fuera de los límites del elemento componible.
El siguiente ejemplo contiene un elemento Box
muy pequeño en el que se puede hacer clic. El objetivo táctil
se expande automáticamente más allá de los límites de Box
, por lo que si presionas
junto a Box
seguirá activando el evento de clic.
@Composable private fun SmallBox() { var clicked by remember { mutableStateOf(false) } Box( Modifier .size(100.dp) .background(if (clicked) Color.DarkGray else Color.LightGray) ) { Box( Modifier .align(Alignment.Center) .clickable { clicked = !clicked } .background(Color.Black) .size(1.dp) ) } }
Para evitar una posible superposición entre áreas táctiles de diferentes elementos componibles, siempre
usa un tamaño mínimo lo suficientemente grande para el elemento componible. En el ejemplo, eso sería
implica usar el modificador sizeIn
para establecer el tamaño mínimo de la caja interna:
@Composable private fun LargeBox() { var clicked by remember { mutableStateOf(false) } Box( Modifier .size(100.dp) .background(if (clicked) Color.DarkGray else Color.LightGray) ) { Box( Modifier .align(Alignment.Center) .clickable { clicked = !clicked } .background(Color.Black) .sizeIn(minWidth = 48.dp, minHeight = 48.dp) ) } }
Agrega etiquetas de clic
Puedes usar una etiqueta de clic para agregar significado semántico al comportamiento de los clics de un elemento componible. Las etiquetas de clic describen lo que sucede cuando el usuario interactúa con el componible. Los servicios de accesibilidad usan etiquetas de clic para ayudar a describir la app a usuarios con necesidades específicas.
Para configurar la etiqueta de clic, pasa un parámetro en el modificador clickable
:
@Composable private fun ArticleListItem(openArticle: () -> Unit) { Row( Modifier.clickable( // R.string.action_read_article = "read article" onClickLabel = stringResource(R.string.action_read_article), onClick = openArticle ) ) { // .. } }
Como alternativa, si no tienes acceso al modificador en el que se puede hacer clic, configura la etiqueta de clic en el modificador semantics:
@Composable private fun LowLevelClickLabel(openArticle: () -> Boolean) { // R.string.action_read_article = "read article" val readArticleLabel = stringResource(R.string.action_read_article) Canvas( Modifier.semantics { onClick(label = readArticleLabel, action = openArticle) } ) { // .. } }
Describe elementos visuales
Cuando defines un elemento Image
o Icon
componible, no hay
forma automática para que el framework de Android comprenda qué es la app
mostrando. Debes pasar una descripción textual del elemento visual.
Imagina una pantalla en la que el usuario pueda compartir la página actual con amigos. Esta pantalla contiene un ícono para compartir en el que se puede hacer clic:
Basándose solamente en el ícono, el framework de Android no puede describirlo a un usuario con discapacidad. El framework de Android necesita una descripción textual adicional de el ícono.
El parámetro contentDescription
describe un elemento visual. Usa una dirección de correo electrónico
cadena, ya que es visible para el usuario.
@Composable private fun ShareButton(onClick: () -> Unit) { IconButton(onClick = onClick) { Icon( imageVector = Icons.Filled.Share, contentDescription = stringResource(R.string.label_share) ) } }
Algunos elementos visuales son puramente decorativos, y es posible que no quieras comunicar
con el usuario. Cuando configuras el parámetro contentDescription
en null
,
le indican al framework de Android que este elemento no está asociado
acciones o estados.
@Composable private fun PostImage(post: Post, modifier: Modifier = Modifier) { val image = post.imageThumb ?: painterResource(R.drawable.placeholder_1_1) Image( painter = image, // Specify that this image has no semantic meaning contentDescription = null, modifier = modifier .size(40.dp, 40.dp) .clip(MaterialTheme.shapes.small) ) }
Depende de ti decidir si un elemento visual específico necesita una contentDescription
. Pregúntate si el elemento transmite información que
el usuario deberá realizar la tarea. Si no es así, es mejor dejar
describe.
Combina elementos
Los servicios de accesibilidad como TalkBack y Accesibilidad con interruptores permiten que los usuarios muevan el enfoque entre los elementos de la pantalla. Es importante que los elementos estén enfocados en el nivel de detalle correcto. Cuando todos los elementos componibles de bajo nivel de la pantalla centrados de forma independiente, los usuarios tienen que interactuar mucho para moverse por la pantalla. Si los elementos se fusionan de manera demasiado agresiva, es posible que los usuarios no entiendan qué los elementos van juntos
Cuando aplicas un modificador clickable
a un elemento componible, Compose
fusiona automáticamente todos los elementos que contiene el elemento componible. Esto también ocurre
ListItem
de elementos dentro de un elemento de lista se combinan y la accesibilidad
servicios los ven como un elemento.
Se puede formar un grupo lógico con un conjunto de elementos componibles, pero ese grupo no admitirá clics ni será parte de un elemento de lista. Querrás la accesibilidad servicios para verlas como un elemento. Por ejemplo, imagina un elemento componible que muestra el avatar del usuario, su nombre y algunos datos adicionales:
Puedes permitir que Compose combine estos elementos con mergeDescendants
.
en el modificador semantics
. De esta manera, los servicios de accesibilidad
seleccionar solo el elemento combinado y todas las propiedades semánticas de los elementos subordinados
se fusionan.
@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 a la vez y se combinan su contenido:
Agrega acciones personalizadas
Observa el siguiente elemento de la lista:
Cuando usas un lector de pantalla como TalkBack para escuchar lo que se muestra en la pantalla, primero selecciona todo el elemento y luego el ícono de marcador.
En una lista larga, esto puede ser muy repetitivo. Un mejor enfoque es
definir una acción personalizada que permita a un usuario agregar el elemento a favoritos Recuerda
también debes quitar de forma explícita el comportamiento del ícono de favoritos
para asegurarse de que no lo seleccione el servicio de accesibilidad. Esta
se completa con el modificador clearAndSetSemantics
:
@Composable private fun PostCardSimple( /* ... */ isFavorite: Boolean, onToggleFavorite: () -> Boolean ) { val actionLabel = stringResource( if (isFavorite) R.string.unfavorite else R.string.favorite ) Row( modifier = Modifier .clickable(onClick = { /* ... */ }) .semantics { // Set any explicit semantic properties customActions = listOf( CustomAccessibilityAction(actionLabel, onToggleFavorite) ) } ) { /* ... */ BookmarkButton( isBookmarked = isFavorite, onClick = onToggleFavorite, // Clear any semantics properties set on this node modifier = Modifier.clearAndSetSemantics { } ) } }
Describe el estado de un elemento
Un elemento componible puede definir un stateDescription
para la semántica que
El framework de Android usa para leer el estado en el que se encuentra el elemento componible. Para
ejemplo, un elemento componible que se puede activar o desactivar puede estar en un estado o un estado "desmarcado"
para cada estado. En algunos casos, es posible que desees anular la descripción del estado predeterminado
las etiquetas que usa Compose. Para hacerlo, especifica de forma explícita el estado
etiquetas de descripción antes de definir un elemento componible como un elemento que se puede activar o desactivar:
@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() } ) ) { /* ... */ } }
Define encabezados
En ocasiones, las apps muestran mucho contenido en una pantalla dentro de un contenedor desplazable. Por ejemplo, una pantalla puede mostrar el contenido completo de un artículo que el usuario está leyendo:
Los usuarios con necesidades de accesibilidad tienen dificultades para navegar por esta pantalla. Para ayudar la navegación, indican qué elementos son encabezados. En el ejemplo anterior, cada el título de la subsección podría definirse como un encabezado para la accesibilidad. Algunos servicios de accesibilidad, como TalkBack, les permiten a los usuarios navegar directamente de un encabezado a otro.
En Compose, para indicar que un elemento componible es un encabezado, se define su
semantics
:
@Composable private fun Subsection(text: String) { Text( text = text, style = MaterialTheme.typography.headlineSmall, modifier = Modifier.semantics { heading() } ) }
Cómo controlar elementos componibles personalizados
Cuando reemplaces ciertos componentes de Material en tu app con debes tener en cuenta las consideraciones de accesibilidad.
Supongamos que reemplazarás el elemento Checkbox
de Material con tu propia implementación.
Podrías olvidarte de agregar el modificador triStateToggleable
, que controla
las propiedades de accesibilidad de este componente.
Como regla general, observa la implementación del componente en la biblioteca de Material e imitar cualquier comportamiento de accesibilidad que encuentres. Además, usa activamente los modificadores de Foundation, en lugar de los modificadores del nivel de IU, ya que incluyen consideraciones de accesibilidad de forma inmediata.
Pruebe la implementación de sus componentes personalizados con varios servicios de accesibilidad para verificar su comportamiento.
Recursos adicionales
- Accesibilidad: conceptos esenciales y técnicas comunes a todo el desarrollo de apps para Android
- Compila apps accesibles: Pasos clave que puedes realizar para que tu app sea más accesible
- Principios para mejorar la aplicación accesibilidad: Los principios clave para tener en cuenta cuando trabajes para hacer que tu aplicación sea más accesible
- Prueba de accesibilidad: Principios y herramientas de prueba para la accesibilidad de Android