多くの Android TV アプリはネイティブ Android コンポーネントで構築されていますが、特にカスタムビューを使用する場合は、サードパーティのフレームワークまたはコンポーネントのユーザー補助機能を考慮することも重要です。
OpenGL や Canvas と直接やり取りするカスタムビュー コンポーネントは、TalkBack やスイッチ アクセスなどのユーザー補助サービスでは適切に動作しない場合があります。
TalkBack をオンにすると、次のような問題が発生する可能性があります。
- アプリでユーザー補助フォーカス(緑色の長方形)が消えることがあります。
- ユーザー補助機能のフォーカスで画面全体の境界が選択される場合もあります。
- ユーザー補助フォーカスが移動できない場合があります。
- D-pad の 4 つの方向キーは、コードで処理しても効果がない場合があります。
アプリで上記の問題が見られた場合は、その AccessibilityNodeInfo
ツリーがユーザー補助サービスに公開されていることをご確認ください。
これ以降は、これらの問題に対処するためのソリューションとベスト プラクティスをいくつか紹介します。
D-pad イベントがユーザー補助サービスで使用される
この問題の根本原因は、キーイベントがユーザー補助サービスで使用されていることです。
図 1 に示すように、TalkBack がオンになっている場合、デベロッパーが定義した D-pad ハンドラに D-pad イベントは渡されません。代わりに、ユーザー補助サービスはキーイベントを受信して、ユーザー補助フォーカスを移動します。カスタム Android コンポーネントは、デフォルトでは画面上の位置に関する情報をユーザー補助サービスに公開しないため、ユーザー補助サービスがユーザー補助のフォーカスを移動してハイライト表示することはできません。
他のユーザー補助サービスも同様に影響を受けます。スイッチ アクセスの使用時に、D-pad イベントが使用される可能性があります。
D-pad イベントはユーザー補助サービスに送信されますが、このサービスでは UI コンポーネントがカスタムビュー内のどこにあるかわからないため、アプリでキーイベントを正しく転送するには AccessibilityNodeInfo
を実装する必要があります。
ユーザー補助サービスに情報を公開する
カスタムビューの場所と説明に関する十分な情報をユーザー補助サービスに提供するには、AccessibilityNodeInfo
を実装して各コンポーネントの詳細を公開します。ユーザー補助サービスがフォーカスを管理できるようにビューの論理関係を定義するには、ExploreByTouchHelper
を実装し、カスタムビューに ViewCompat.setAccessibilityDelegate(View, AccessibilityDelegateCompat)
を使用して設定します。
ExploreByTouchHelper
を実装する場合は、次の 4 つの抽象メソッドをオーバーライドします。
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 用のカスタムビューのユーザー補助のサンプルをご覧ください。