VoiceOver en iOS: solución de problemas comunes

Cuando se compromete a adaptar la aplicación para ciegos, a menudo algo sale mal: o el orden se perderá, entonces el foco se colocará en el lugar equivocado. Por otro lado, está UX, que es fácil pasar por alto porque no eres consciente de posibles problemas. En este artículo trataremos problemas típicos y sus soluciones.



La adaptación de la aplicación iOS es un gran tema, no todo encaja en un artículo, por lo que los lanzo en una serie.

  1. Control de voz y VoiceOver: cómo adaptar la aplicación para ciegos o quietos .
  2. VoiceOver en iOS: cada control se comporta de manera diferente.
  3. VoiceOver en iOS: Solución de problemas comunes.
  4. La diferencia entre la implementación de VoiceOver, Voice Control y las pruebas de IU. (En progreso)

En la primera parte, tratamos la adaptación de aplicaciones para ciegos usando VoiceOver: controles firmados, agrupados, navegación fija. En la segunda parte, fuimos más allá y examinamos las "características" que se pueden dar a los controles para mejorar su trabajo para las personas ciegas y, en general, mejorar la usabilidad de la aplicación.

Hoy continuaremos trabajando para adaptar la pantalla de la pizza: cambiaremos el orden de rastreo, resumiremos la información de compra, arreglaremos la ventana modal y mejoraremos el indicador de carga.

Reordenar controles


Si no establece el orden correcto para pasar los controles para VoiceOver, lo más probable es que omita y lea los elementos en el orden incorrecto que desee. Por ejemplo, esto sucedió con los botones "cerrar" y "a la cesta".

La pantalla se desplazará y los botones están arriba UIScrollView. Resulta que VoiceOver primero intenta omitir todos los elementos dentro UIScrollViewy solo luego encuentra los botones superiores. Para el usuario, este comportamiento de VoiceOver será incorrecto: los botones están en la parte superior, por lo que la iteración y la puntuación deberían comenzar con ellos.

Para comenzar, primero descubramos cómo VoiceOver determina el orden de los controles. Lo hace de esta manera: toma elementos de una propiedad accessibilityElements. Por defecto, todos viewellos están ahí isAccessibilityElement = true.

Ahora podemos poner los botones al principio anulando accessibilityElements:

override var accessibilityElements: [Any]? {
    get {
        var elements = [Any]()
            
        elements.append(contentsOf: [closeButton, cartButton])
        elements.append(contentsOf: contentScrollView.accessibilityElements)
            
        return elements
    }
    set { }
}

Agrupar a través de shouldGroupAccessibilityChildren


Por lo general, VoiceOver intenta leer elementos en un orden natural, de izquierda a derecha, de arriba a abajo:



si tiene controles agrupados, entonces necesita VoiceOver para saltar al elemento más cercano en la agrupación, y no en orden de lectura. Establezca .shouldGroupAccessibilityChildren = true, y el orden comenzará a tener en cuenta la proximidad de los elementos. La propiedad debe establecerse como padre viewpara todos los elementos.



Señale el primer elemento para enfocar


Otro problema de orden de lectura es que cuando VoiceOver abre la pantalla por primera vez, selecciona el elemento superior izquierdo. Muy a menudo, este es el botón de retroceso. Por un lado, esto le permite regresar rápidamente a la pantalla anterior si comete un error. Por otro lado, así es como perdemos nuestra comprensión de en qué pantalla estamos. Puede corregir la situación si establece manualmente el foco en el control deseado.

¿Qué hace Apple?
Es extraño que UINavigationControllerponga el foco en el botón "Atrás", podría ponerlo en el título de la pantalla que se abre. Desde el punto de vista de la conveniencia, me parece correcto centrarme en el título o el primer control, por lo que brindamos más información sobre la nueva pantalla. Puede regresar con un gesto de fregado .

Puede reorganizar el enfoque utilizando la función de alerta UIAccessibility.post(notification: …). Se necesitan dos parámetros:

  • Una de las especies UIAccessibility.Notification.
  • El objeto al que se debe aplicar la alerta. Muy a menudo, esta es una línea con texto o un objeto que debe seleccionarse después de la notificación.

Puede poner el foco en el encabezado en viewDidLoad:

override func viewDidLoad() {
    super.viewDidLoad()
        
    UIAccessibility.post(notification: .screenChanged,
                         argument: titleLabel);
}

Puede transferir el objeto en el que desea enfocar o el texto que se pronunciará.

Tipos de alertas para objetos


  • .screenChanged — , . - .
  • .layoutChanged — . , , «» .
  • .announcement — . . , . , .

    DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) {
    		UIAccessibility.post(notification: .announcement,
                             argument: text)
    }
  • .pageScrolled.UIScrollView « 3 5», . , , .
  • .pauseAssistiveTechnology .resumeAssistiveTechnology —  VoiceOver.

Mostrar ventanas modales de forma nativa


Cuando trabajas con VoiceOver puedes (y lo harás) disparar todas las jambas permitidas en el desarrollo. Por ejemplo, creamos un mensaje y, para que los mensajes comenzaran desde abajo, decidimos voltear UITableViewy luego voltear todas las celdas. Visualmente, todo está bien, pero la lista se desplazará boca abajo con tres dedos en VoiceOver.

También enfrentamos el problema de que no podíamos cambiar los ingredientes de ninguna manera, porque no era posible enfocar la ventana. Sucedió porque mostramos la vista, y no UIViewControllercon un UIPresentationController.VoiceOver especial al que se dirige .firstResponder, y el nuestro viewno.



Si no hay tiempo para reescribir, puede viewestablecer la propiedad para accessibilityViewIsModal. Entonces VoiceOver se centrará solo en eso view.

override var accessibilityViewIsModal: Bool {
    get { return true }
    set {}
}

Para ser honesto, nunca funcionó para mí, y nosotros UIPresentationController.

Alinear marcos invisibles


El orden de lectura se cuenta por cuadros, a veces da resultados inesperados. Por ejemplo, ampliamos el marco del botón "i" para que sea más fácil hacer clic. Pero resultó ser más alto que el marco del nombre de la pizza, por lo que el primer elemento de enfoque fue el botón "i". Aunque es pequeño, está a la derecha y generalmente no es tan importante.



Puede cambiar el orden de lectura accessibilityElements, pero mostraré una forma diferente. VoiceOver usa la propiedad accessibilityFrame, solo por defecto coincide con el marco habitual. Hay varias soluciones:

  1. Anule la subclase de control y devuelva un valor reducido.
  2. Establecer el marco correcto afuera.
  3. Simplemente ajuste el marco para que quede al ras con la inscripción.

Pero es importante que este marco esté en las coordenadas de la pantalla. Para la conversión simple hay una función UIAccessibility.convertToScreenCoordinates.

También se puede usar para combinar controles. Por ejemplo, debe combinar el conmutador y su firma, de modo que el elemento se agrandará, será más fácil hacer clic en él, la duplicación innecesaria desaparecerá.

override func layoutSubviews() {
        super.layoutSubviews()
        repeatSwitch.accessibilityLabel = repeatLabel.text
        repeatSwitch.accessibilityFrame = UIAccessibility.convertToScreenCoordinates(
                repeatSwitch.frame.union(repeatLabel.frame).insetBy(dx: -12, dy: -12),
                in: repeatSwitch.superview!)
}

También amplié el enfoque usando .inset, es más conveniente presionar.



Usando el marco y AccessibilityContainerpuede hacer gráficos y tablas disponibles.

Resumir la acción principal.


Esto es más sobre UX, pero te lo diré de todos modos. Una persona con visión normal lee fácilmente todos los ajustes de la pantalla, pero para esta persona ciega, debe ordenar manualmente todos los controles. Puede facilitar el proceso y resumir todos los cambios en el botón Comprar.

Por ejemplo, para obtener el botón "Comprar". Agregue el tocino, quite los jalapeños. Precio 434₽ », no necesita escribir nada inusual en el código, solo recopile la línea con agregado / eliminado:

accessibilityTraits = .button
accessibilityLabel = ""
accessibilityValue = " ,  .  434₽" 

Y no olvides firmar el indicador de descarga


Si después de agregar un producto al carrito bloquea brevemente la interfaz y descarga algo, no olvide hacer que el indicador de descarga esté disponible:

  1. Use la alerta para enfocarse en el indicador.
  2. Dale un nombre al foco. Por ejemplo, cargando.
  3. Póngalo accessibilityViewIsModal.
  4. Avísame cuando finalice la descarga.

Si después de cargar muestra una nueva pantalla, VoiceOver cambiará el foco, por lo que quedará claro que la descarga ha finalizado. En casos más complicados, puede decir esto explícitamente o incluso agregar vibración .

¿Qué hace Apple?
Curiosamente, Safari funciona con esto en iOS 13: durante la carga de la página, hace un clic cada segundo, y cuando la página se carga lo hace * woop-dumb *. Por desgracia, desde el lado de la API esto aún no está disponible, estamos esperando iOS 14.



Para adaptar la pantalla, utilizamos diferentes enfoques: cambiamos el orden de los botones, indicamos el primer elemento para enfocar, arreglamos la ventana modal, resumimos la configuración en el botón principal y trabajamos en la conveniencia de la aplicación. Este conocimiento es suficiente para adaptar casi cualquier aplicación. Adelante.

La próxima vez hablaré sobre la diferencia entre la implementación de VoiceOver, Voice Control y las pruebas de IU.
Para no perderse el siguiente artículo, suscríbase a mi canal Dodo Pizza Mobile .

All Articles