Android 기기를 사용하는 일부 사용자는 여타 사용자와는 다른 접근성 기능을 필요로 합니다. 동일한 접근성 기능을 필요로 하는 특정 사용자 그룹을 지원하기 위해 Android 프레임워크는 개발자가 접근성 서비스를 만들 수 있는 기능을 제공합니다. 이 접근성 서비스는 개발자에게 앱의 콘텐츠를 제공하고 자동으로 앱을 운영합니다.
Android는 다음을 포함하여 여러 시스템 접근성 서비스를 제공합니다.
- 음성 안내 지원: 시력이 약하거나 시각 장애가 있는 사용자를 지원합니다. 합성된 음성을 통해 콘텐츠를 알리고 앱에서 사용자 동작에 응답하여 작업을 실행합니다.
- 스위치 제어: 거동 장애가 있는 사용자를 지원합니다. 상호작용 요소를 강조표시하고 사용자가 버튼을 누르면 이에 응답하여 작업을 실행합니다. 1개 또는 2개의 버튼만 사용하여 기기를 제어할 수 있게 합니다.
접근성 기능이 필요한 사용자가 앱을 성공적으로 사용하도록 지원하려면 앱이 이 페이지에 설명된 권장사항을 따라야 합니다. 이 권장사항은 더욱 접근성 높은 앱 만들기에 설명된 주요 가이드라인을 기반으로 합니다.
다음 각 권장사항은 앱의 접근성을 더욱 향상할 수 있습니다.
- 요소에 라벨 지정
- 사용자는 앱 내에 있는 상호작용이 가능한 중요한 각 UI 요소의 콘텐츠 및 목적을 이해할 수 있어야 합니다.
- 시스템 위젯 사용 또는 확장
- 자체 맞춤 뷰를 만드는 대신 프레임워크에 포함된 뷰 요소를 활용하여 빌드합니다. 프레임워크의 뷰 및 위젯 클래스는 이미 앱에 필요한 대부분의 접근성 기능을 제공합니다.
- 색상 이외의 큐 사용
- 사용자는 UI의 요소 카테고리를 명확하게 구분할 수 있어야 합니다. 카테고리를 구분하려면 패턴 및 위치를 색상과 함께 사용하여 카테고리의 차이를 표현합니다.
- 미디어 콘텐츠의 접근성 높이기
- 앱의 동영상 또는 오디오 콘텐츠를 사용하는 사용자가 시각 또는 청각적인 큐에 전적으로 의존할 필요가 없도록 앱의 동영상 또는 오디오 콘텐츠에 설명을 추가해 보세요.
요소에 라벨 지정
앱에서 상호작용이 가능한 각 UI 요소에 관한 설명이 포함된 유용한 라벨을 사용자에게 제공하는 것이 중요합니다. 각 라벨은 특정 요소의 의미와 목적을 설명해야 합니다. 음성 안내 지원 기능과 같은 스크린 리더는 이 서비스에 의존하는 사용자에게 이러한 라벨을 알릴 수 있습니다.
대부분의 경우 이 요소가 포함된 레이아웃 리소스 파일에 특정 UI 요소의 설명을 지정합니다. 더욱 접근성 높은 앱 만들기 가이드에 설명된 것처럼 대개 contentDescription
속성을 사용하여 라벨을 추가하지만 다음 섹션에 설명된 몇 가지 다른 라벨 지정 기법에 유의해야 합니다.
수정 가능한 요소
EditText
객체와 같은 수정 가능한 요소에 라벨을 지정할 때는 이 텍스트 예를 스크린 리더에서 사용할 수 있게 하는 것 외에도 요소 자체에 올바른 입력의 예를 제공하는 텍스트를 표시하는 것이 좋습니다. 이러한 상황에서는 다음 스니펫에 표시된 대로 android:hint
속성을 사용할 수 있습니다.
<!-- The hint text for en-US locale would be "Apartment, suite, or building". --> <EditText android:id="@+id/addressLine2" android:hint="@string/aptSuiteBuilding" ... />
이 상황에서 View
객체의 android:labelFor
속성은 EditText
요소의 ID로 설정되어야 합니다. 자세한 내용은 한 요소가 다른 요소를 설명하는 요소 쌍에 라벨을 지정하는 방법을 설명하는 섹션을 참조하세요.
한 요소가 다른 요소를 설명하는 요소 쌍
일반적으로 특정 EditText
요소에는 상응하는 View
객체가 있어 사용자가 EditText
요소 내에 입력해야 하는 콘텐츠를 설명합니다. Android 4.2(API 수준 17) 이상을 실행하는 기기에서는 View
객체의 android:labelFor
속성을 설정하여 이 관계를 나타낼 수 있습니다.
다음 스니펫에서는 이러한 요소 쌍에 라벨을 지정하는 예를 보여줍니다.
<!-- Label text for en-US locale would be "Username:" --> <TextView android:id="@+id/usernameLabel" ... android:text="@string/username" android:labelFor="@+id/usernameEntry" /> <EditText android:id="@+id/usernameEntry" ... /> <!-- Label text for en-US locale would be "Password:" --> <TextView android:id="@+id/passwordLabel" ... android:text="@string/password android:labelFor="@+id/passwordEntry" /> <EditText android:id="@+id/passwordEntry" android:inputType="textPassword" ... />
컬렉션의 요소
컬렉션의 요소에 라벨을 추가할 때 각 라벨은 고유해야 합니다. 라벨이 고유해야 라벨을 알릴 때 시스템의 접근성 서비스에서 화면에 표시되는 요소를 정확히 하나만 참조할 수 있습니다. 이러한 대응 관계를 통해 사용자가 UI를 순환했을 때 또는 이미 찾은 요소로 포커스를 이동했을 때 이를 알 수 있습니다.
특히 RecyclerView
객체와 같이 재사용된 레이아웃 내 요소에 추가 텍스트 또는 컨텍스트 정보를 포함하여 각 하위 요소가 고유하게 식별되도록 해야 합니다.
이렇게 하려면 다음 코드 스니펫과 같이 어댑터 구현의 일부로 콘텐츠 설명을 설정합니다.
Kotlin
data class MovieRating(val title: String, val starRating: Integer) class MyMovieRatingsAdapter(private val myData: Array<MovieRating>): RecyclerView.Adapter<MyMovieRatingsAdapter.MyRatingViewHolder>() { class MyRatingViewHolder(val ratingView: ImageView) : RecyclerView.ViewHolder(ratingView) override fun onBindViewHolder(holder: MyRatingViewHolder, position: Int) { val ratingData = myData[position] holder.ratingView.contentDescription = "Movie ${position}: " + "${ratingData.title}, ${ratingData.starRating} stars" } }
자바
public class MovieRating { private String title; private int starRating; // ... public String getTitle() { return title; } public int getStarRating() { return starRating; } } public class MyMovieRatingsAdapter extends RecyclerView.Adapter<MyAdapter.MyRatingViewHolder> { private MovieRating[] myData; public static class MyRatingViewHolder extends RecyclerView.ViewHolder { public ImageView ratingView; public MyRatingViewHolder(ImageView iv) { super(iv); ratingView = iv; } } @Override public void onBindViewHolder(MyRatingViewHolder holder, int position) { MovieRating ratingData = myData[position]; holder.ratingView.setContentDescription("Movie " + position + ": " + ratingData.getTitle() + ", " + ratingData.getStarRating() + " stars") } }
관련 콘텐츠 그룹
앱에서 노래의 세부정보나 메시지의 속성과 같이 자연스러운 그룹을 형성하는 여러 UI 요소를 표시하는 경우 대개 ViewGroup
의 서브클래스인 컨테이너 내에 이러한 요소를 정렬합니다. 컨테이너 객체의 android:screenReaderFocusable
속성을 true
로 설정하고 각 내부 객체의 android:focusable
속성을 false
로 설정합니다. 이렇게 설정하면 접근성 서비스에서 내부 요소의 콘텐츠 설명을 하나의 알림에 차례로 표시할 수 있습니다.
이렇게 관련 요소를 통합하면 사용자가 보조 기술을 사용하여 화면에 표시된 정보를 더 효율적으로 찾을 수 있습니다.
다음 스니펫에는 서로 관련된 콘텐츠 부분이 포함되어 있습니다. 즉, 컨테이너 요소(ConstraintLayout
의 인스턴스)에는 android:screenReaderFocusable
속성이 true
로 설정되어 있으며 내부 TextView
요소에는 각각 android:focusable
속성이 false
로 설정되어 있습니다.
<!-- In response to a single user interaction, accessibility services announce both the title and the artist of the song. --> <ConstraintLayout android:id="@+id/song_data_container" ... android:screenReaderFocusable="true"> <TextView android:id="@+id/song_title" ... android:focusable="false" android:text="@string/my_song_title" /> <TextView android:id="@+id/song_artist" android:focusable="false" android:text="@string/my_songwriter" /> </ConstraintLayout>
접근성 서비스는 내부 요소의 설명을 하나의 표현으로 알려주기 때문에 각 설명을 최대한 짧게 유지하면서 요소의 의미를 전달하는 것이 중요합니다.
맞춤 그룹 라벨
원하는 경우 그룹 자체에 관한 콘텐츠 설명을 제공하여 플랫폼의 기본 그룹화 및 그룹의 내부 요소 설명 순서를 재정의할 수 있습니다.
다음 스니펫에서는 맞춤설정된 그룹 설명의 예를 보여줍니다.
<!-- In response to a single user interaction, accessibility services announce the custom content description for the group. --> <ConstraintLayout android:id="@+id/song_data_container" ... android:screenReaderFocusable="true" android:contentDescription="@string/title_artist_best_song"> <TextView android:id="@+id/song_title" ... <!-- Content ignored by accessibility services --> android:text="@string/my_song_title" /> <TextView android:id="@+id/song_artist" <!-- Content ignored by accessibility services --> android:text="@string/my_songwriter" /> </ConstraintLayout>
중첩된 그룹
앱 인터페이스에 축제 이벤트의 일별 목록과 같은 다차원 정보가 표시되는 경우 내부 그룹 컨테이너에 android:screenReaderFocusable
속성을 사용합니다. 이러한 라벨 지정 방식은 화면의 콘텐츠를 발견하는 데 필요한 알림의 수와 각 알림의 길이 간에 적절한 균형을 제공합니다.
다음 코드 스니펫에서는 대규모 그룹 내에서 그룹에 라벨을 지정하는 한 가지 방법을 보여줍니다.
<!-- In response to a single user interaction, accessibility services announce the events for a single stage only. --> <ConstraintLayout android:id="@+id/festival_event_table" ... > <ConstraintLayout android:id="@+id/stage_a_event_column" android:screenReaderFocusable="true"> <!-- UI elements that describe the events on Stage A. --> </ConstraintLayout> <ConstraintLayout android:id="@+id/stage_b_event_column" android:screenReaderFocusable="true"> <!-- UI elements that describe the events on Stage B. --> </ConstraintLayout> </ConstraintLayout>
텍스트 내 제목
일부 앱에서는 제목을 사용해 화면에 표시되는 텍스트 그룹을 요약합니다. 특정 View
요소에서 제목을 표현하는 경우 요소의 android:accessibilityHeading
속성을 true
로 설정하여 접근성 서비스의 용도를 나타낼 수 있습니다.
접근성 서비스 사용자는 단락 또는 단어가 아닌 제목 사이를 탐색하도록 선택할 수 있습니다. 이러한 유연성을 통해 텍스트 탐색 환경이 개선됩니다.
접근성 창(pane) 제목
Android 9(API 수준 28) 이상에서는 화면의 창(pane)에 접근성을 고려한 제목을 제공할 수 있습니다. 접근성을 위해 창(pane)은 프래그먼트 콘텐츠와 같이 시각적으로 구분되는 창(window)의 부분입니다. 접근성 서비스에서 창(window)과 유사한 창(pane) 동작을 이해할 수 있도록 앱의 창(pane)에 내용을 잘 나타내는 제목을 제공해야 합니다. 그러면 접근성 서비스에서 창(pane)의 모양이나 콘텐츠가 변경될 때 더 세분화된 정보를 사용자에게 제공할 수 있습니다.
창(pane)의 제목을 지정하려면 다음 스니펫과 같이 android:accessibilityPaneTitle
속성을 사용합니다.
<!-- Accessibility services receive announcements about content changes that are scoped to either the "shopping cart view" section (top) or "browse items" section (bottom) --> <MyShoppingCartView android:id="@+id/shoppingCartContainer" android:accessibilityPaneTitle="@string/shoppingCart" ... /> <MyShoppingBrowseView android:id="@+id/browseItemsContainer" android:accessibilityPaneTitle="@string/browseProducts" ... />
장식 요소
UI의 요소가 시각적 간격용 또는 시각적 표시용으로만 존재하면 android:contentDescription
속성을 "null"
로 설정합니다.
앱에서 Android 4.1(API 수준 16) 이상을 실행하는 기기만 지원한다면 대신 이렇게 순전히 장식적인 요소의 android:importantForAccessibility
속성을 "no"
로 설정할 수 있습니다.
시스템 위젯 확장
핵심 사항: 앱의 UI를 디자인할 때 가능한 한 Android 클래스 계층 구조의 매우 아래에 있는 시스템 제공 위젯을 사용하거나 확장합니다. 계층 구조의 매우 아래에 있는 시스템 제공 위젯에는 앱에 필요한 대부분의 접근성 기능이 이미 있습니다. 더 일반적인 View
, ViewCompat
, Canvas
및 CanvasCompat
클래스에서 고유한 위젯을 생성하는 것보다 이러한 시스템 제공 위젯을 확장하는 것이 더 쉽습니다.
고도로 맞춤설정된 환경이나 게임 레벨에 필요할 수 있는 View
또는 Canvas
를 직접 확장해야 한다면 맞춤 뷰의 접근성 높이기를 참조하세요.
이 섹션에서는 TriSwitch
라는 특수한 유형의 Switch
를 구현하는 방법을 설명합니다. 각 TriSwitch
인스턴스를 통해 사용자가 3가지의 가능한 상태 간에 전환할 수 있다는 점을 제외하면 TriSwitch
객체는 Switch
객체와 유사하게 작동합니다.
클래스 계층 구조 매우 아래에서 확장
다음과 같이 Switch
객체는 계층 구조의 여러 프레임워크 UI 클래스에서 상속됩니다.
View ↳ TextView ↳ Button ↳ CompoundButton ↳ Switch
새 TriSwitch
클래스는 Switch
클래스에서 직접 확장하는 것이 가장 좋습니다. 이렇게 하면 Android 접근성 프레임워크가 TriSwitch
클래스에 필요한 대부분의 접근성 기능을 제공합니다.
- 접근성 작업: 접근성 서비스가
TriSwitch
객체에서 실행되는 각각의 가능한 사용자 입력을 에뮬레이션하는 방법을 시스템에 알립니다. (View
에서 상속됨) - 접근성 이벤트: 화면을 새로 고치거나 업데이트할 때
TriSwitch
객체의 모양이 변경될 수 있는 모든 가능한 방법에 관해 접근성 서비스에 알립니다. (View
에서 상속됨) - 특성: 표시되는 텍스트의 콘텐츠와 같은 각
TriSwitch
객체에 관한 세부정보입니다. (TextView
에서 상속됨) - 상태 정보: '선택됨' 또는 '선택 해제됨'과 같은
TriSwitch
객체의 현재 상태에 관한 설명입니다. (CompoundButton
에서 상속됨) - 상태에 관한 텍스트 설명: 각 상태가 나타내는 사항에 관한 텍스트 기반 설명입니다. (
Switch
에서 상속됨)
Switch
및 슈퍼클래스의 이러한 집계 동작은 거의 TriSwitch
객체에 관해 원하는 동작입니다. 따라서 구현 시 가능한 상태 수를 2개에서 3개로 확장하는 데 집중할 수 있습니다.
맞춤 이벤트 정의
시스템 위젯을 확장할 때 사용자가 그 위젯과 상호작용하는 방식의 측면을 변경할 수 있습니다. 접근성 서비스가 마치 사용자가 위젯과 직접 상호작용한 것처럼 앱의 위젯을 업데이트할 수 있도록 이러한 상호작용 변경사항을 정의하는 작업이 중요합니다.
일반적인 가이드라인은 재정의하는 모든 뷰 기반 콜백에 대해 ViewCompat.replaceAccessibilityAction()
을 재정의하여 상응하는 접근성 작업을 다시 정의해야 한다는 것입니다.
앱의 테스트에서 ViewCompat.performAccessibilityAction()
을 호출하여 이러한 재정의된 작업의 동작을 검증할 수 있습니다.
이 원칙이 TriSwitch 객체에서 작동하는 방식
일반적인 Switch
객체와 달리 TriSwitch
객체를 탭하면 3가지의 가능한 상태가 순환됩니다. 따라서 상응하는 ACTION_CLICK
접근성 작업을 다음과 같이 업데이트해야 합니다.
Kotlin
class TriSwitch(context: Context) : Switch(context) { // 0, 1, or 2. var currentState: Int = 0 private set init { updateAccessibilityActions() } private fun updateAccessibilityActions() { ViewCompat.replaceAccessibilityAction(this, ACTION_CLICK, action-label) { view, args -> moveToNextState() }) } private fun moveToNextState() { currentState = (currentState + 1) % 3 } }
자바
public class TriSwitch extends Switch { // 0, 1, or 2. private int currentState; public int getCurrentState() { return currentState; } public TriSwitch() { updateAccessibilityActions(); } private void updateAccessibilityActions() { ViewCompat.replaceAccessibilityAction(this, ACTION_CLICK, action-label, (view, args) -> moveToNextState()); } private void moveToNextState() { currentState = (currentState + 1) % 3; } }
색상 이외의 큐 사용
색약이 있는 사용자를 지원하려면 색상 이외의 큐를 사용해 앱 화면 내에 있는 UI 요소를 구별하세요. 이러한 기법에는 다양한 도형 또는 크기를 사용하거나 텍스트 또는 시각적 패턴을 제공하거나 요소의 차이점을 표시하는 오디오 기반 또는 터치 기반(햅틱) 반응을 추가하는 것이 포함될 수 있습니다.
그림 1에서는 활동의 두 가지 버전을 보여줍니다. 한 버전에서는 워크플로에서 실행 가능한 두 작업을 구분하는 데 색상만 사용합니다. 다른 버전에서는 두 옵션의 차이를 강조표시하기 위해 색상 외에 도형 및 텍스트를 포함하는 권장사항을 사용합니다.
미디어 콘텐츠의 접근성 높이기
동영상 클립 또는 오디오 녹음과 같은 미디어 콘텐츠가 포함된 앱을 개발한다면 다양한 유형의 접근성이 필요한 사용자가 이 자료를 이해할 수 있도록 지원해 보세요. 특히 다음과 같은 작업을 하는 것이 좋습니다.
- 사용자가 미디어를 일시중지 또는 중지하고 볼륨을 변경하며 자막을 전환할 수 있는 컨트롤을 포함합니다.
- 동영상에서 워크플로를 완료하는 데 필수적인 정보를 표시하는 경우 동일한 콘텐츠를 스크립트와 같은 대체 형식으로 제공합니다.
참고 자료
앱의 접근성을 높이는 방법을 자세히 알아보려면 다음 추가 리소스를 참조하세요.