虽然许多 Android TV 应用都是使用原生 Android 组件构建的,但同样重要的是要考虑第三方框架或组件的可访问性,尤其是在使用自定义视图时。
直接与 OpenGL 或 Canvas 交互的自定义视图组件可能无法与 Talkback 和 Switch Access 等辅助功能服务良好配合。
请考虑在打开 Talkback 时可能发生的一些问题
- 辅助功能焦点(绿色矩形)可能在您的应用中消失。
- 辅助功能焦点可能选择整个屏幕的边界。
- 辅助功能焦点可能无法移动。
- D 形方向键可能没有效果,即使您的代码正在处理它们。
如果在您的应用中观察到任何这些问题,请检查您的应用是否将其AccessibilityNodeInfo
树公开给辅助功能服务。
本指南的其余部分提供了一些解决这些问题的解决方案和最佳实践。
D 形方向键事件被辅助功能服务消耗
此问题的根本原因是辅助功能服务会消耗按键事件。
如图 1 所示,当 Talkback 打开时,D 形方向键事件不会传递给开发者定义的 D 形方向键处理程序。相反,辅助功能服务会接收按键事件,以便它们可以移动辅助功能焦点。由于自定义 Android 组件默认情况下不会将有关其在屏幕上位置的信息公开给辅助功能服务,因此辅助功能服务无法移动辅助功能焦点以突出显示它们。
其他辅助功能服务也会受到类似的影响:使用 Switch Access 时,D 形方向键事件也可能被消耗。
由于 D 形方向键事件会提交给辅助功能服务,并且该服务不知道自定义视图中 UI 组件的位置,因此您必须为您的应用实现AccessibilityNodeInfo
以正确转发按键事件。
向辅助功能服务公开信息
为了向辅助功能服务提供有关自定义视图的位置和描述的足够信息,请实现AccessibilityNodeInfo
以公开每个组件的详细信息。要定义视图的逻辑关系,以便辅助功能服务可以管理焦点,请实现ExploreByTouchHelper
并使用ViewCompat.setAccessibilityDelegate(View, AccessibilityDelegateCompat)
为自定义视图设置它。
在实现ExploreByTouchHelper
时,覆盖其四个抽象方法
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)
有关更多详细信息,请观看Google I/O 2013 - 在 Android 上启用盲人和低视力辅助功能或阅读有关填充辅助功能事件的更多信息。
最佳实践
必需:
AccessibilityNodeInfo.getBoundsInScreen()
必须定义组件的位置。必需:
AccessibilityNodeInfo.setVisibleToUser()
必须反映组件的可见性。必需:
AccessibilityNodeInfo.getContentDescription()
必须指定 Talkback 用于播报的内容描述。指定
AccessibilityNodeInfo.setClassName()
,以便服务可以区分组件类型。在实现
performAction()
时,使用相应的AccessibilityEvent
反映操作。要实现更多操作类型,例如
ACTION_CLICK
,请使用performAction()
中的相应逻辑调用AccessibilityNodeInfo.addAction(ACTION_CLICK)
。在适用情况下,反映
setFocusable()
、setClickable()
、setScrollable()
和类似方法的组件状态。查看
AccessibilityNodeInfo
的文档,以确定辅助功能服务可以更好地与您的组件交互的其他方法。
示例
请参阅Android TV 的自定义视图辅助功能示例,以了解向使用自定义视图的应用添加辅助功能支持的最佳实践。