Accesibilidad
20 January 2022

Aplicando la accesibilidad en Flutter: El widget Semantics

Actualmente los dispositivos móviles, tanto con el sistema operativo Android como con el de iOS, pueden ser utilizados por personas con alguna discapacidad, ya sea motriz, auditiva o visual.

No obstante, en múltiples ocasiones, las aplicaciones no se desarrollan teniendo en cuenta las herramientas de accesibilidad que proporciona cada framework.

En el caso de Flutter, contamos con un widget que nos permite añadir información adicional a los diferentes elementos del árbol de Widget, a fin de facilitar su comprensión y uso por una persona con discapacidad.

En esta explicación me enfocaré en algunas características relacionadas con los lectores de pantalla, que son la principal herramienta de accesibilidad utilizada por personas con discapacidad visual.

El lector de pantalla en Android se denomina Talkback, mientras que en iOS es llamado VoiceOver, y en ambas plataformas puede ser activado desde los ajustes del teléfono.

Nota importante: Si se activa el lector de pantalla para hacer pruebas, el comportamiento del toque en pantalla cambia, por lo que al tocar un elemento éste será leído por el lector de pantalla, y para activarlo habrá qué tocarlo dos veces consecutivas de forma rápida.

Descripción

Según la propia página de Flutter:

Semantics es un widget que anota el árbol de widgets con una descripción del significado de los widgets. Es utilizado por herramientas de accesibilidad, motores de búsqueda y otro software de análisis semántico para determinar el significado de la aplicación.

Esto quiere decir que a través de este widget se puede proporcionar información complementaria, muchas veces necesaria, y que esta información será interpretada por las tecnologías de asistencia.

Para proporcionar esta información, es necesario embeber el widget al que queramos añadirle dicha información con el widget Semantics, y fijar las propiedades que sean necesarias.

A continuación mostraré tres ejemplos del uso de este widget, utilizando como base el proyecto que se crea por defecto en Flutter, el del contador.

Áreas vivas, o Live Regions

Las áreas vivas son aquellas partes de la interfaz que pueden cambiar, y que sería necesario que un usuario de lector de pantalla se diera cuenta de ese cambio.

En el ejemplo del contador, al presionar el botón “Increment”, el número de clicks cambia, pero un usuario de lector de pantalla necesitaría desplazarse hacia el número (tocarlo) para poder darse cuenta que realmente ha cambiado.

Para resolver este problema, podría utilizarse la propiedad liveRegion del widget Semantics de la siguiente manera:

Semantics(
  liveRegion: true,
  child: Text(
    '$_counter',
    style: Theme.of(context).textTheme.headline4,
  ),
)

De esta manera, cada vez que este widget se redibuje porque su valor cambia, dicho valor será anunciado por el lector de pantalla de forma automática.

Unir widgets de forma semántica

Cuando un usuario de lector de pantalla navega por la interfaz, lo hace generalmente en el orden que tienen los widgets al ser definidos, usando gestos de deslizamiento a izquierda y derecha. Cada vez que se realiza el gesto, el lector de pantalla verbaliza el anterior o siguiente widget, según sea el caso. De esta manera no necesita conocer la posición de un elemento en la pantalla para poder llegar a él.

En ocasiones existen widgets que no tienen sentido que se naveguen de forma separada, sino como un solo componente, es el caso de los dos text del contador.

Para ello puede utilizarse el widget MergeSemantics de la siguiente manera:

body: Center(
  child: MergeSemantics(
    child: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        const Text(
          'You have pushed the button this many times:',
        ),
        Semantics(
          liveRegion: true,
          child: Text(
            '$_counter',
            style: Theme.of(context).textTheme.headline4,
          ),
        ),
      ],
    ),
  ),
),

De esta forma, al navegar por la interfaz, un usuario de lector de pantalla percibe ambos text como si fueran uno solo. Incluso ahora al presionar el botón “Increment”, el lector de pantalla lee automáticamente no solo el número que cambia, sino todo el nuevo componente incluyendo la frase.

Etiquetar elementos gráficos

En muchas ocasiones se utilizan imágenes o iconos para diseñar la interfaz gráfica. Algunas veces las imágenes cumplen solo un fin decorativo, por lo que pueden envolverse con el widget Semantics, y aplicar la propiedad hidden, con lo que dichas imágenes serán ignoradas en la navegación de los usuarios de lector de pantalla.

No obstante, en otras ocasiones puede resultar necesario que esas imágenes o iconos sean leídas, por ejemplo si se utilizan para indicar una acción, como es el caso del botón de Increment.

En este caso no es necesario envolver con el widget Semantics, ya que algunos elementos ya cuentan con la propiedad necesaria, la cual se establece de la siguiente manera:

floatingActionButton: FloatingActionButton(
  onPressed: _incrementCounter,
  tooltip: 'Increment',
  child: const Icon(
    Icons.add,
    semanticLabel: 'Counter',
  ),
),

De esta forma, cuando el usuario toca el botón (solo lo toca, no lo activa) el lector de pantalla lee el tooltip mas la etiqueta del icono, en este caso “Increment Counter”.

Conclusión

Estos son solo tres ejemplos del uso de este widget, pero hay muchos más, tal como asignar diferentes roles a widgets, por ejemplo indicar que un widget de imagen cumple función de un botón, entre muchos otros.

La documentación completa puede consultarse en la página Accessibility widgets \| Flutter, y el código fuente completo del archivo dart puede revisarse en Semantics Widget Flutter (github.com)

ernesto.blanco

Desarrollador y consultor de accesibilidad web y móvil