Kotlin accesible: escribimos código que no abandona a los usuarios

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Por qué la accesibilidad en Kotlin es un superpoder, no una casilla de verificación

\n\n

Imagina: escribiste una aplicación genial en Kotlin. Hermoso Material Design, animaciones fluidas, streams reactivos. Estás orgulloso del código. Pero luego resulta que una persona con baja visión no puede presionar el botón «Comprar», porque TalkBack lo lee como «botón sin etiquetar». O un usuario con temblor en las manos falla al tocar un pequeño interruptor.

\n\n

La accesibilidad no es una burocracia aburrida. Se trata de que tu código en Kotlin funcione para todos. Según la OMS, más de mil millones de personas tienen alguna discapacidad. Ignorarlos significa perder audiencia y, francamente, ser un mal desarrollador.

\n\n

En este artículo, veremos cómo escribir código accesible en Kotlin sin dolor. Sin toneladas de código repetitivo. Con ejemplos vivos que puedes copiar y pegar ahora mismo.

\n\n

Principios básicos: ContentDescription es tu mejor amigo

\n\n

El fallo más común en accesibilidad es la falta de descripción para los elementos de la interfaz. El sistema TalkBack (lector de pantalla en Android) no sabe leer imágenes o iconos. Necesita texto.

\n\n

En Kotlin, esto se hace mediante el atributo contentDescription. Pero no solo «Botón», sino con sentido.

\n\n

Mal ejemplo (no hagas esto)

\n
imageView.contentDescription = "Botón"
\n\n

Buen ejemplo

\n
binding.fabAddTask.contentDescription = "Agregar nueva tarea"
\n\n

Si el icono es decorativo (solo adorno) — establece contentDescription = null para que TalkBack lo ignore.

\n\n
// Icono decorativo — no distraemos al usuario\nbinding.decorativeIcon.contentDescription = null
\n\n

Consejo: Usa recursos de cadena (strings.xml) para soportar localización. No hardcodees texto en español en los archivos Kotlin.

\n\n

Marcado semántico: le decimos al sistema qué es importante

\n\n

Las View estándar (Button, TextView) funcionan bastante bien, pero los componentes personalizados a menudo rompen la accesibilidad. En Kotlin podemos definir explícitamente la semántica.

\n\n

Añadimos un rol al elemento

\n
binding.customView.importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_YES\nbinding.customView.accessibilityDelegate = object : View.AccessibilityDelegate() {\n    override fun onInitializeAccessibilityNodeInfo(host: View, info: AccessibilityNodeInfo) {\n        super.onInitializeAccessibilityNodeInfo(host, info)\n        info.text = "Valor actual: ${viewModel.value}"\n        info.contentDescription = "Control deslizante de volumen"\n    }\n}
\n\n

Este código le dice al sistema: «Oye, esto no es solo un cuadrado, ¡es un control deslizante!». TalkBack entenderá que el elemento es interactivo y podrá interactuar correctamente.

\n\n

Agrupación de elementos

\n

Si tienes una tarjeta de producto con imagen, precio y nombre — combínalos en un solo foco. De lo contrario, el usuario escuchará tres elementos por separado.

\n\n
binding.cardProduct.apply {\n    isFocusable = true\n    contentDescription = "Producto: ${product.name}, precio: ${product.price} pesos"\n}
\n\n

Ahora TalkBack leerá toda la información de un solo clic.

\n\n

Navegación por acción: teclado y D-pad

\n\n

No todos los usuarios tocan la pantalla con el dedo. Algunos usan teclado (mediante OTG) o D-pad (control remoto). Tu aplicación debe poder manejarse sin contacto táctil.

\n\n

En Kotlin, esto se resuelve con focusable y el orden de foco (nextFocusDown, nextFocusForward).

\n\n
binding.buttonNext.nextFocusForwardId = R.id.buttonConfirm\nbinding.buttonConfirm.nextFocusDownId = R.id.buttonCancel
\n\n

Verifica que todos los elementos interactivos reciban foco. Un error común es un TextView con ClickableSpan (enlace en el texto). Por defecto no recibe foco. Lo corregimos:

\n\n
binding.textWithLink.movementMethod = LinkMovement                

Blogs

Book Recommendations