Android TV의 맞춤 뷰 접근성 지원
컬렉션을 사용해 정리하기
내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.
많은 Android TV 앱이 기본 Android 구성요소로 제작되지만
서드 파티 쿠키의 접근성을 고려하는 것도
(특히 맞춤 뷰를 사용하는 경우) 프레임워크 또는 구성요소를 관리할 수 있습니다.
OpenGL 또는 캔버스와 직접 상호작용하는 맞춤 뷰 구성요소가 제대로 작동하지 않을 수 있음
TalkBack, 스위치 제어와 같은 접근성 서비스와 함께
TalkBack이 전환될 때 발생할 수 있는 다음 문제를 고려하세요.
날짜:
- 앱에서 접근성 포커스 (녹색 직사각형)가 사라질 수 있습니다.
- 접근성 포커스가 전체 화면의 경계를 선택할 수도 있습니다.
- 접근성 포커스를 이동하지 못할 수 있습니다.
- D패드의 4개 방향 키는 코드에서 처리 중이더라도 아무런 영향을 미치지 않을 수 있습니다.
앱에서 이러한 문제가 발견되면
앱이 AccessibilityNodeInfo
를 노출함
트리를 접근성 서비스에 추가합니다.
이 가이드의 나머지 부분에서는 이러한 문제를 해결하기 위한 몇 가지 솔루션과 권장사항을 제공합니다.
접근성 서비스에서 사용하는 D패드 이벤트
이 문제의 근본 원인은 주요 이벤트를 접근성이 사용하기 때문입니다.
제공합니다
그림 1. TalkBack을 사용 설정하거나 사용 중지한 상태에서 시스템이 작동하는 방식을 보여주는 다이어그램
그림 1과 같이 TalkBack이 켜져 있으면 D패드 이벤트
개발자가 정의한 D패드 핸들러로 전달되지 않습니다. 대신
접근성 서비스는 주요 이벤트를 수신하여
접근성에 중점을 두고 있습니다. 맞춤 Android 구성요소는 기본적으로 맞춤 Android 구성요소를
접근성 서비스에 화면상의 위치에 관한 정보
접근성 서비스에서 해당 기능을 강조표시하기 위해 접근성 포커스를 이동할 수 없습니다.
다른 접근성 서비스도 마찬가지로 영향을 받습니다. D패드 이벤트도
100%는 소비됩니다.
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
자바
// 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의 접근성
또는 접근성 이벤트 채우기에 대해 자세히 알아보세요.
권장사항
샘플
다음에 관한 권장사항을 보려면 Android TV용 맞춤 보기 접근성 샘플을 참조하세요.
맞춤 뷰를 사용하여 앱에 접근성 지원을 추가합니다.
이 페이지에 나와 있는 콘텐츠와 코드 샘플에는 콘텐츠 라이선스에서 설명하는 라이선스가 적용됩니다. 자바 및 OpenJDK는 Oracle 및 Oracle 계열사의 상표 또는 등록 상표입니다.
최종 업데이트: 2025-07-27(UTC)
[null,null,["최종 업데이트: 2025-07-27(UTC)"],[],[],null,["# Custom view accessibility support on Android TV\n\nWhile many Android TV apps are built with native Android components, it's\nalso important to consider the accessibility of third-party\nframeworks or components, especially when using [custom views](https://developer.android.com/guide/topics/ui/custom-components).\n\nCustom view components interfacing directly with OpenGL or Canvas might not work well\nwith accessibility services like Talkback and Switch Access.\n\nConsider some of the following issues that might occur with Talkback switched\non:\n\n- The accessibility focus (a green rectangle) might disappear in your app.\n- The accessibility focus might select the boundary of the whole screen.\n- The accessibility focus might not be movable.\n- The four direction keys on the D-pad might have no effect, even if your code is handling them.\n\n\u003cbr /\u003e\n\nIf you observe any of these issues in your app, check that your\napp exposes its [`AccessibilityNodeInfo`](https://developer.android.com/reference/android/view/accessibility/AccessibilityNodeInfo)\ntree to the accessibility services.\n\nThe remainder of this guide provides some solutions and best practices to address these issues.\n\nD-pad events are consumed by accessibility services\n---------------------------------------------------\n\nThe root cause of this issue is that key events are consumed by accessibility\nservices.\n\n\n**Figure 1.** Diagrams depicting how the system functions with Talkback on and off.\n\nAs illustrated in figure 1, when Talkback is switched on, D-pad events\nare not passed to the D-pad handler defined by developer. Instead,\naccessibility services receive the key events so they can move the\naccessibility focus. Because custom Android components don't by default expose\ninformation to accessibility services about their position on the screen,\naccessibility services can't move the accessibility focus to highlight them.\n\nOther accessibility services are similarly affected: D-pad events might also be\nconsumed when using Switch Access.\n\nBecause D-pad events are submitted to accessibility services, and\nthat service doesn't know where UI components are in a custom view,\nyou must implement `AccessibilityNodeInfo` for your app to forward the\nkey events correctly.\n\nExpose information to accessibility services\n--------------------------------------------\n\nTo provide accessibility services with sufficient information about the\nlocation and description of custom views, implement [`AccessibilityNodeInfo`](/reference/android/view/accessibility/AccessibilityNodeInfo)\nto expose details for each component.\nTo define the logical relationship of views so that accessibility services can\nmanage focus, implement [`ExploreByTouchHelper`](https://developer.android.com/reference/androidx/customview/widget/ExploreByTouchHelper)\nand set it using\n[`ViewCompat.setAccessibilityDelegate(View, AccessibilityDelegateCompat)`](https://developer.android.com/reference/androidx/core/view/ViewCompat#setAccessibilityDelegate(android.view.View,%20androidx.core.view.AccessibilityDelegateCompat))\nfor custom views.\n\nWhen implementing `ExploreByTouchHelper`, override its four abstract methods: \n\n### Kotlin\n\n```kotlin\n// Return the virtual view ID whose view is covered by the input point (x, y).\nprotected fun getVirtualViewAt(x: Float, y: Float): Int\n\n// Fill the virtual view ID list into the input parameter virtualViewIds.\nprotected fun getVisibleVirtualViews(virtualViewIds: List\u003cInt\u003e)\n\n// For the view whose virtualViewId is the input virtualViewId, populate the\n// accessibility node information into the AccessibilityNodeInfoCompat parameter.\nprotected fun onPopulateNodeForVirtualView(virtualViewId: Int, @NonNull node: AccessibilityNodeInfoCompat)\n\n// Set the accessibility handling when perform action.\nprotected fun onPerformActionForVirtualView(virtualViewId: Int, action: Int, @Nullable arguments: Bundle): Boolean\n```\n\n### Java\n\n```java\n// Return the virtual view ID whose view is covered by the input point (x, y).\nprotected int getVirtualViewAt(float x, float y)\n\n// Fill the virtual view ID list into the input parameter virtualViewIds.\nprotected void getVisibleVirtualViews(List\u003cInteger\u003e virtualViewIds)\n\n// For the view whose virtualViewId is the input virtualViewId, populate the\n// accessibility node information into the AccessibilityNodeInfoCompat parameter.\nprotected void onPopulateNodeForVirtualView(int virtualViewId, @NonNull AccessibilityNodeInfoCompat node)\n\n// Set the accessibility handling when perform action.\nprotected boolean onPerformActionForVirtualView(int virtualViewId, int action, @Nullable Bundle arguments)\n```\n\nFor more details, watch [Google I/O 2013 - Enabling Blind and Low-Vision\nAccessibility on Android](https://www.youtube.com/watch?v=ld7kZRpMGb8&t=1196)\nor read more about [populating accessibility events](https://developer.android.com/guide/topics/ui/accessibility/custom-views#populate-events).\n\nBest practices\n--------------\n\n- **Required:** [`AccessibilityNodeInfo.getBoundsInScreen()`](https://developer.android.com/reference/android/view/accessibility/AccessibilityNodeInfo#getBoundsInScreen(android.graphics.Rect))\n must define the position of the component.\n\n- **Required:** [`AccessibilityNodeInfo.setVisibleToUser()`](https://developer.android.com/reference/android/view/accessibility/AccessibilityNodeInfo#setVisibleToUser(boolean))\n must reflect the visibility of the component.\n\n- **Required:** [`AccessibilityNodeInfo.getContentDescription()`](https://developer.android.com/reference/android/view/accessibility/AccessibilityNodeInfo#getContentDescription())\n must specify the content description for Talkback to announce.\n\n- Specify [`AccessibilityNodeInfo.setClassName()`](https://developer.android.com/reference/android/view/accessibility/AccessibilityNodeInfo#setClassName(java.lang.CharSequence))\n so services can distinguish the component type.\n\n- When implementing [`performAction()`](https://developer.android.com/reference/android/view/accessibility/AccessibilityNodeInfo#performAction(int)),\n reflect the action using a corresponding [`AccessibilityEvent`](https://developer.android.com/reference/android/view/accessibility/AccessibilityEvent).\n\n- To implement more action types, such as `ACTION_CLICK`, invoke\n [`AccessibilityNodeInfo.addAction(ACTION_CLICK)`](https://developer.android.com/reference/android/view/accessibility/AccessibilityNodeInfo#addAction(android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction))\n using the corresponding logic in `performAction()`.\n\n- When applicable, reflect the component state for [`setFocusable()`](https://developer.android.com/reference/android/view/accessibility/AccessibilityNodeInfo#setFocusable(boolean)),\n [`setClickable()`](https://developer.android.com/reference/android/view/accessibility/AccessibilityNodeInfo#setClickable(boolean)),\n [`setScrollable()`](https://developer.android.com/reference/android/view/accessibility/AccessibilityNodeInfo#setScrollable(boolean)),\n and similar methods.\n\n- Review the documentation for [`AccessibilityNodeInfo`](/reference/android/view/accessibility/AccessibilityNodeInfo)\n to identify other ways in which accessibility services can better interact with\n your components.\n\nSample\n------\n\nConsult the [custom view accessibility sample for Android TV](/training/tv/accessibility/custom-views-sample) to see best practices for\nadding accessibility support to apps using custom views."]]