雖然許多 Android TV 應用程式都是利用原生 Android 元件建構而成,但也必須考量第三方架構或元件的無障礙功能,尤其是使用自訂檢視畫面時。
直接與 OpenGL 或 Canvas 互動的自訂檢視畫面元件可能無法順暢地與 TalkBack 和切換控制功能等無障礙服務搭配運作。
請考慮開啟 Talkback 開啟時會發生的一些問題:
- 應用程式中的無障礙功能焦點 (綠色矩形) 可能會消失。
- 無障礙焦點可能會選取整個畫面的界線。
- 無障礙焦點可能無法移動。
- 即使程式碼會處理 D-pad 的四個方向按鍵,也沒有任何作用。
如果您發現應用程式發生上述任何問題,請檢查應用程式是否已向無障礙服務公開其 AccessibilityNodeInfo
樹狀結構。
本指南的其餘部分提供了一些解決方案和最佳做法,協助您解決這些問題。
無障礙服務會使用 D-Pad 事件
這個問題的根本原因是無障礙服務會取用重要事件。
如圖 1 所示,開啟 Talkback 時,D-Pad 事件不會傳遞至開發人員定義的 D-Pad 處理常式。無障礙服務會改為接收按鍵事件,以便移動無障礙焦點。由於自訂 Android 元件預設不會向無障礙服務顯示在畫面上位置的相關資訊,因此無障礙服務無法移動無障礙服務焦點,並醒目顯示這些元件。
其他無障礙服務也同樣受到影響:使用切換控制功能時,也可能會耗用 D-Pad 事件。
由於 D-Pad 事件會提交至無障礙服務,且該服務不知道 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)
詳情請參閱「2013 年 Google I/O 大會 - 在 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 的自訂檢視畫面無障礙功能範例,瞭解使用自訂檢視畫面為應用程式新增無障礙功能支援的最佳做法。