Si bien muchas apps para Android TV se compilan con componentes nativos de Android, también es importante tener en cuenta la accesibilidad de los frameworks o componentes de terceros, en especial cuando se usan vistas personalizadas.
Es posible que los componentes de vistas personalizadas que interactúan directamente con OpenGL o Canvas no funcionen bien con los servicios de accesibilidad, como TalkBack y Accesibilidad con interruptores.
Ten en cuenta algunos de los siguientes problemas que pueden ocurrir con TalkBack activado:
- El foco de accesibilidad (un rectángulo verde) podría desaparecer en tu app.
- El enfoque de accesibilidad puede seleccionar el límite de toda la pantalla.
- Es posible que el enfoque de accesibilidad no se pueda mover.
- Es posible que las cuatro teclas de dirección del pad direccional no tengan efecto, incluso si tu código las controla.
Si observas alguno de estos problemas en tu app, verifica que exponga su árbol AccessibilityNodeInfo
a los servicios de accesibilidad.
En el resto de esta guía, se proporcionan algunas soluciones y prácticas recomendadas para abordar estos problemas.
Los servicios de accesibilidad consumen los eventos de pad direccional
La causa raíz de este problema es que los servicios de accesibilidad consumen los eventos de clave.
Como se ilustra en la figura 1, cuando TalkBack está activado, los eventos de pad direccional no se pasan al controlador de pad direccional definido por el desarrollador. En cambio, los servicios de accesibilidad reciben los eventos clave para que puedan mover el enfoque de accesibilidad. Debido a que los componentes personalizados de Android no exponen de forma predeterminada información a los servicios de accesibilidad sobre su posición en la pantalla, estos no pueden mover el enfoque de accesibilidad para destacarlos.
Otros servicios de accesibilidad se ven afectados de manera similar: los eventos de pad direccional también pueden consumirse cuando se usa la Accesibilidad con interruptores.
Debido a que los eventos de pad direccional se envían a los servicios de accesibilidad, y ese servicio no sabe dónde se encuentran los componentes de la IU en una vista personalizada, debes implementar AccessibilityNodeInfo
para que tu app reenvíe los eventos clave de forma correcta.
Exponer información a los servicios de accesibilidad
Para proporcionar servicios de accesibilidad con suficiente información sobre la ubicación y la descripción de las vistas personalizadas, implementa AccessibilityNodeInfo
para exponer los detalles de cada componente.
Para definir la relación lógica de las vistas de modo que los servicios de accesibilidad puedan administrar el enfoque, implementa ExploreByTouchHelper
y configúralo con ViewCompat.setAccessibilityDelegate(View, AccessibilityDelegateCompat)
para las vistas personalizadas.
Cuando implementes ExploreByTouchHelper
, anula sus cuatro métodos abstractos:
Kotlin
// Return the virtual view ID whose view is covered by the input point (x, y). protected fun getVirtualViewAt(x: Float, y: Float): Int // Fill the virtual view ID list into the input parameter virtualViewIds. protected fun getVisibleVirtualViews(virtualViewIds: List<Int>) // For the view whose virtualViewId is the input virtualViewId, populate the // accessibility node information into the AccessibilityNodeInfoCompat parameter. protected fun onPopulateNodeForVirtualView(virtualViewId: Int, @NonNull node: AccessibilityNodeInfoCompat) // Set the accessibility handling when perform action. protected fun onPerformActionForVirtualView(virtualViewId: Int, action: Int, @Nullable arguments: Bundle): Boolean
Java
// Return the virtual view ID whose view is covered by the input point (x, y). protected int getVirtualViewAt(float x, float y) // Fill the virtual view ID list into the input parameter virtualViewIds. protected void getVisibleVirtualViews(List<Integer> virtualViewIds) // For the view whose virtualViewId is the input virtualViewId, populate the // accessibility node information into the AccessibilityNodeInfoCompat parameter. protected void onPopulateNodeForVirtualView(int virtualViewId, @NonNull AccessibilityNodeInfoCompat node) // Set the accessibility handling when perform action. protected boolean onPerformActionForVirtualView(int virtualViewId, int action, @Nullable Bundle arguments)
Para obtener más información, mira Google I/O 2013: Cómo habilitar la accesibilidad de personas ciegas y de baja visión en Android o lee más sobre cómo completar eventos de accesibilidad.
Prácticas recomendadas
Obligatorio:
AccessibilityNodeInfo.getBoundsInScreen()
debe definir la posición del componente.Obligatorio:
AccessibilityNodeInfo.setVisibleToUser()
debe reflejar la visibilidad del componente.Obligatorio:
AccessibilityNodeInfo.getContentDescription()
debe especificar la descripción del contenido para que TalkBack lo anuncie.Especifica
AccessibilityNodeInfo.setClassName()
para que los servicios puedan distinguir el tipo de componente.Cuando implementes
performAction()
, refleja la acción con unAccessibilityEvent
correspondiente.Para implementar más tipos de acciones, como
ACTION_CLICK
, invoca aAccessibilityNodeInfo.addAction(ACTION_CLICK)
con la lógica correspondiente enperformAction()
.Cuando corresponda, refleja el estado del componente para
setFocusable()
,setClickable()
,setScrollable()
y métodos similares.Revisa la documentación de
AccessibilityNodeInfo
para identificar otras formas en las que los servicios de accesibilidad pueden interactuar mejor con tus componentes.
Muestra
Consulta el ejemplo de accesibilidad de vistas personalizadas para Android TV a fin de ver las prácticas recomendadas para agregar compatibilidad de accesibilidad a las apps que usan vistas personalizadas.