Android 앱 접근성(Accessibility) 완벽 가이드 — TalkBack, contentDescription, 글자 크기와 UI 테스트
Android 앱을 개발할 때 화면 디자인과 기능 구현에 집중하다 보면 놓치기 쉬운 부분이 있습니다.
바로 **접근성(Accessibility)**입니다.
예를 들어 조류 도감 앱에서 새 사진 옆에 하트 모양의 좋아요 버튼을 배치했다고 가정하겠습니다.
화면을 보는 사용자는 하트 아이콘의 의미를 쉽게 이해할 수 있습니다. 하지만 TalkBack을 사용하는 사람에게 버튼이 단순히 '버튼'이라고만 읽힌다면 어떤 기능인지 알기 어렵습니다.
또 다른 예로 사용자가 스마트폰의 글자 크기를 크게 설정했는데, 앱에서 TextView의 높이를 고정해 두었다면 글자가 잘리거나 버튼을 누르기 어려워질 수 있습니다.
이런 문제는 장애가 있는 사용자뿐 아니라 고령자, 작은 화면을 사용하는 사람, 한 손으로 스마트폰을 사용하는 사람에게도 영향을 줍니다.
이번 글에서는 Android 앱의 접근성을 개선하기 위해 다음 내용을 살펴보겠습니다.
Android 접근성의 기본 개념
TalkBack과 접근성 트리
contentDescription설정아이콘 버튼과 이미지 접근성
RecyclerView 항목 및 좋아요 상태 처리
BottomNavigationView와 ViewPager2 접근성
글자 크기 확대와 Android 14 비선형 글꼴 크기 조절
최소 터치 영역과 색상 대비
입력 오류 및 상태 변경 안내
접근성 자동화 테스트와 수동 검증
개발 환경: Kotlin, XML View, AndroidX, minSdk 24 이상. 코드 예제는 개별 기능 설명을 위한 것이며, 실제 프로젝트의 ViewBinding 이름과 리소스에 맞게 조정해야 합니다.
1. Android 접근성이란?
접근성은 다양한 사용자가 앱의 기능과 정보를 이용할 수 있도록 설계하는 것입니다.
대표적으로 다음과 같은 상황을 고려합니다.
| 사용자 상황 | 필요한 접근성 |
|---|---|
| 화면을 보기 어려움 | 화면 읽기 기능, 의미 있는 설명 |
| 작은 글씨를 읽기 어려움 | 글자 크기 확대 |
| 손가락 움직임이 불편함 | 충분한 터치 영역 |
| 색상 구분이 어려움 | 색상 외의 상태 표현 |
| 청각 정보 이용이 어려움 | 자막과 시각적 안내 |
| 키보드나 스위치로 조작 | 논리적인 포커스 순서 |
Android에서는 TalkBack, Switch Access, 글자 크기 및 화면 확대 등의 접근성 기능을 제공합니다.
앱 개발자는 이러한 기능과 호환되는 UI를 구성해야 합니다.
2. TalkBack이란?
TalkBack은 Android의 화면 읽기 기능입니다.
사용자가 화면의 요소를 탐색하면 해당 요소의 이름, 역할, 상태 등을 음성으로 안내합니다.
예를 들어 다음과 같은 버튼이 있다고 가정하겠습니다.
<ImageButton
android:id="@+id/buttonFavorite"
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_favorite" />화면에는 하트 아이콘이 표시되지만 TalkBack에서는 의미가 충분히 전달되지 않을 수 있습니다.
이때 다음과 같이 설명을 추가할 수 있습니다.
android:contentDescription="@string/favorite_add"strings.xml에는 다음과 같이 작성합니다.
<string name="favorite_add">좋아요 추가</string>이제 화면 읽기 사용자는 버튼의 기능을 이해하기 쉬워집니다.
contentDescription 올바르게 사용하기
3. contentDescription의 역할
contentDescription은 화면에 표시되는 시각적 요소의 의미를 접근성 서비스에 전달할 때 사용합니다.
특히 다음 요소에 유용합니다.
아이콘만 있는 버튼
의미 있는 이미지
이미지로 표시된 상태
텍스트가 없는 클릭 요소
하지만 모든 View에 무조건 contentDescription을 추가하는 것은 좋은 방법이 아닙니다.
이미 화면에 표시된 텍스트를 TalkBack이 읽을 수 있다면 별도의 설명이 불필요할 수 있습니다.
4. 아이콘 버튼에는 기능을 설명하기
예를 들어 검색 버튼이 있습니다.
<ImageButton
android:id="@+id/buttonSearch"
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_search"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/search" /><string name="search">검색</string>버튼의 모양보다 실제로 수행하는 동작을 설명하는 것이 좋습니다.
예를 들어 '돋보기 그림'보다는 '검색'이 더 적절합니다.
5. 장식용 이미지에는 설명을 추가하지 않기
모든 이미지가 정보를 전달하는 것은 아닙니다.
예를 들어 카드 배경의 장식 이미지라면 화면 읽기 사용자가 해당 이미지를 탐색할 필요가 없습니다.
<ImageView
android:layout_width="match_parent"
android:layout_height="120dp"
android:src="@drawable/bg_decoration"
android:contentDescription="@null"
android:importantForAccessibility="no" />이렇게 하면 불필요한 접근성 탐색을 줄일 수 있습니다.
단, 이미지 자체가 중요한 정보를 전달한다면 숨겨서는 안 됩니다.
6. 의미 있는 이미지에는 정보를 설명하기
조류 도감 앱에서 새 사진은 중요한 콘텐츠입니다.
예를 들어 다음과 같이 설명할 수 있습니다.
binding.imageBird.contentDescription =
getString(
R.string.bird_photo_description,
bird.nameKor
)<string name="bird_photo_description">%1$s 사진</string>결과적으로 '참새 사진'처럼 읽힐 수 있습니다.
다만 같은 카드에서 이미 '참새'라는 텍스트를 읽고 있다면 중복 설명이 되는지 확인해야 합니다.
이미지가 별도의 정보를 제공하지 않는 경우에는 설명을 줄이거나 카드 전체의 접근성 구성을 조정하는 것이 좋습니다.
동적으로 변하는 상태 처리
7. 좋아요 버튼의 상태를 알려주기
좋아요 버튼은 누를 때마다 상태가 바뀝니다.
따라서 처음에 설정한 설명을 그대로 유지해서는 안 됩니다.
private fun updateFavoriteButton(
isFavorite: Boolean
) {
binding.buttonFavorite.isSelected =
isFavorite
binding.buttonFavorite.contentDescription =
getString(
if (isFavorite) {
R.string.favorite_remove
} else {
R.string.favorite_add
}
)
}<string name="favorite_add">좋아요 추가</string>
<string name="favorite_remove">좋아요 해제</string>이렇게 하면 현재 버튼을 눌렀을 때 어떤 동작이 수행되는지 알 수 있습니다.
8. stateDescription 활용하기
버튼의 동작과 현재 상태를 구분해서 전달할 수도 있습니다.
ViewCompat.setStateDescription(
binding.buttonFavorite,
if (isFavorite) {
getString(R.string.state_selected)
} else {
getString(R.string.state_not_selected)
}
)<string name="state_selected">선택됨</string>
<string name="state_not_selected">선택되지 않음</string>ViewCompat.setStateDescription()은 AndroidX Core에서 제공하는 호환성 API입니다.
사용 중인 AndroidX Core 버전에서 해당 API를 지원하는지 확인해야 합니다.
상태 설명과 콘텐츠 설명이 같은 정보를 지나치게 반복하지 않도록 실제 TalkBack으로 확인하는 것이 좋습니다.
RecyclerView 접근성
9. RecyclerView에서 발생하는 문제
RecyclerView는 여러 항목을 반복해서 표시합니다.
예를 들어 조류 도감 앱의 목록이 다음과 같다고 가정하겠습니다.
참새
Passer montanus
♡ 좋아요
직박구리
Hypsipetes amaurotis
♥ 좋아요각 항목 안에 이미지, 이름, 학명, 버튼이 들어갑니다.
이때 접근성 구조가 잘못되면 사용자가 하나의 항목을 탐색하기 위해 불필요하게 많은 포커스 이동을 해야 할 수 있습니다.
반대로 카드 전체를 하나의 요소로 묶어 버리면 좋아요 버튼을 개별적으로 누르기 어려워질 수도 있습니다.
10. 카드 전체 클릭과 내부 버튼 구분하기
카드 전체를 누르면 상세 화면으로 이동하고, 내부 하트 버튼은 좋아요를 변경하는 구조를 생각해 보겠습니다.
조류 카드
├── 사진
├── 국명
├── 학명
└── 좋아요 버튼이 경우 카드와 좋아요 버튼이 각각 의미 있는 동작을 수행합니다.
따라서 내부 버튼까지 무조건 접근성 탐색에서 제외해서는 안 됩니다.
카드에 요약 설명을 제공하면서 좋아요 버튼은 독립적인 접근성 요소로 유지하는 방식이 좋습니다.
11. RecyclerView ViewHolder 예제
fun bind(bird: BirdItem) {
binding.textNameKor.text =
bird.nameKor
binding.textNameScientific.text =
bird.scientificName
binding.root.contentDescription =
context.getString(
R.string.bird_item_description,
bird.nameKor,
bird.scientificName
)
binding.buttonFavorite.contentDescription =
context.getString(
if (bird.isFavorite) {
R.string.favorite_remove
} else {
R.string.favorite_add
}
)
ViewCompat.setStateDescription(
binding.buttonFavorite,
context.getString(
if (bird.isFavorite) {
R.string.state_selected
} else {
R.string.state_not_selected
}
)
)
}<string name="bird_item_description">%1$s, 학명 %2$s</string>위 코드는 기본적인 설명 예제입니다.
실제 프로젝트에서는 카드 루트가 접근성 요소로 합쳐지는 방식, 자식 요소의 탐색 가능 여부, 클릭 처리 등을 함께 확인해야 합니다.
특히 카드에 contentDescription을 추가하는 것만으로 항상 원하는 포커스 구조가 만들어지는 것은 아닙니다.
12. RecyclerView 항목 갱신 시 주의사항
좋아요 상태가 변경되면 RecyclerView 항목이 다시 바인딩될 수 있습니다.
이때 다음 문제가 발생할 수 있습니다.
TalkBack 포커스가 예상치 못한 위치로 이동
전체 목록이 다시 그려짐
상태 변경이 음성으로 전달되지 않음
가능하면 DiffUtil과 ListAdapter를 이용해 변경된 항목만 갱신하는 것이 좋습니다.
또한 단순한 상태 변경을 위해 매번 notifyDataSetChanged()를 호출하는 방식은 피하는 것이 좋습니다.
BottomNavigationView 접근성
13. 하단 내비게이션의 접근성
Android 앱에서는 BottomNavigationView를 자주 사용합니다.
예를 들어 다음과 같은 메뉴입니다.
홈 | 검색 | 좋아요 | 설정Material Components의 BottomNavigationView는 기본적으로 접근성 기능을 제공합니다.
따라서 일반적인 텍스트 메뉴에 불필요하게 별도의 contentDescription을 추가할 필요는 없습니다.
대신 다음 사항을 확인해야 합니다.
메뉴 이름이 명확한지
선택된 메뉴 상태가 전달되는지
아이콘만으로 의미를 전달하지 않는지
글자 크기를 키워도 메뉴가 정상적으로 표시되는지
14. 메뉴 제목은 간결하게 작성하기
<item
android:id="@+id/menu_search"
android:icon="@drawable/ic_search"
android:title="@string/menu_search" /><string name="menu_search">검색</string>메뉴 제목은 '돋보기'보다 '검색'처럼 기능을 설명하는 표현이 좋습니다.
ViewPager2 접근성
15. 이미지 슬라이드 접근성
조류 상세 화면에서 ViewPager2를 이용해 여러 사진을 보여준다고 가정하겠습니다.
참새 사진 1 / 3
참새 사진 2 / 3
참새 사진 3 / 3이미지를 넘길 때 현재 몇 번째 사진인지 알려주면 화면 읽기 사용자가 위치를 파악하기 쉬워집니다.
16. 이미지 설명에 순서 포함하기
val description = context.getString(
R.string.bird_gallery_image,
birdName,
position + 1,
totalCount
)
binding.imageBird.contentDescription =
description<string name="bird_gallery_image">%1$s 사진, %2$d장 중 %3$d번째</string>이 예제는 이미지 자체가 접근성 포커스를 받는 경우에 유용합니다.
사진 전환마다 별도의 음성 안내를 강제로 발생시키는 방식은 사용자에게 방해가 될 수 있으므로 신중하게 적용해야 합니다.
글자 크기 확대 대응
17. dp와 sp의 차이
Android에서는 일반적으로 화면 요소 크기에 dp, 텍스트 크기에 sp를 사용합니다.
android:layout_width="48dp"
android:textSize="16sp"sp는 사용자가 설정한 글자 크기를 반영하는 데 사용합니다.
텍스트 크기를 dp로 지정하면 사용자의 글자 크기 설정을 적절하게 반영하지 못할 수 있습니다.
따라서 텍스트에는 sp를 사용하는 것이 기본 원칙입니다.
18. TextView 높이를 고정하지 않기
다음과 같은 레이아웃을 생각해 보겠습니다.
<TextView
android:layout_width="match_parent"
android:layout_height="40dp"
android:textSize="18sp"
android:text="@string/bird_description" />글자 크기가 커지면 텍스트가 잘릴 수 있습니다.
가능하면 다음과 같이 작성합니다.
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
android:text="@string/bird_description" />단, wrap_content만 사용한다고 모든 문제가 해결되는 것은 아닙니다.
부모 레이아웃의 높이, 제약 조건, 스크롤 가능 여부도 함께 확인해야 합니다.
19. Android 14의 비선형 글꼴 크기 조절
Android 14(API 34)에서는 큰 글꼴 크기에 대한 비선형 글꼴 스케일링이 도입되었습니다.
이 기능은 작은 글자와 큰 글자의 크기 변화가 동일한 비율로 적용되지 않을 수 있다는 의미입니다.
따라서 다음과 같이 단순 계산하는 방식은 주의해야 합니다.
val scaledSize =
textSize * resources.configuration.fontScale특히 글꼴 크기를 수동으로 계산하거나 sp를 임의로 dp로 변환하는 로직이 있다면 실제 기기에서 확인해야 합니다.
기본적으로는 Android의 텍스트 크기 처리 API와 sp 단위를 활용하는 것이 좋습니다.
터치 영역과 색상 대비
20. 최소 터치 영역 48dp
Android 접근성 설계에서는 일반적으로 48dp × 48dp 이상의 터치 영역을 권장합니다.
예를 들어 아이콘 자체는 24dp여도 버튼의 터치 영역은 더 크게 구성할 수 있습니다.
<ImageButton
android:id="@+id/buttonFavorite"
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="12dp"
android:src="@drawable/ic_favorite"
android:contentDescription="@string/favorite_add" />이렇게 하면 시각적인 아이콘은 작게 유지하면서 누르기 쉬운 영역을 확보할 수 있습니다.
터치 영역이 충분하지 않으면 작은 버튼을 정확하게 누르기 어려울 수 있습니다.
21. TouchDelegate 활용
디자인상 버튼의 실제 크기를 늘리기 어렵다면 TouchDelegate를 이용해 터치 영역을 확장할 수 있습니다.
binding.buttonFavorite.post {
val rect = Rect()
binding.buttonFavorite.getHitRect(rect)
val extra = 12.dpToPx()
rect.inset(-extra, -extra)
binding.parentLayout.touchDelegate =
TouchDelegate(
rect,
binding.buttonFavorite
)
}위 코드는 dpToPx() 확장 함수가 구현되어 있다고 가정합니다.
또한 TouchDelegate는 부모 View의 터치 처리 범위 안에서 동작하므로 부모의 크기와 다른 클릭 요소와의 충돌을 고려해야 합니다.
가능하면 먼저 레이아웃 자체에서 충분한 터치 영역을 확보하는 것이 좋습니다.
22. 색상만으로 상태를 표현하지 않기
좋아요 버튼이 선택되었을 때 빨간색으로 바뀐다고 가정하겠습니다.
선택 안 됨 → 회색 하트
선택됨 → 빨간색 하트하지만 색상 구분이 어려운 사용자는 상태를 이해하기 어려울 수 있습니다.
따라서 다음과 같은 요소를 함께 활용하는 것이 좋습니다.
채워진 하트와 빈 하트의 모양 차이
상태 설명
선택 여부를 나타내는 텍스트
충분한 색상 대비
색상은 정보를 보조하는 수단으로 사용하고, 유일한 정보 전달 수단으로 사용하지 않는 것이 좋습니다.
23. 텍스트 색상 대비
WCAG의 일반적인 AA 기준에서는 다음 대비 비율을 참고할 수 있습니다.
| 구분 | 권장 최소 대비 |
|---|---|
| 일반 텍스트 | 4.5:1 |
| 큰 텍스트 | 3:1 |
| 의미 있는 UI 구성 요소 | 3:1 |
큰 텍스트의 기준은 WCAG에서 별도로 정의합니다.
또한 실제 접근성은 색상 대비만으로 결정되지 않습니다.
글자 크기, 글꼴 두께, 배경 이미지, 터치 영역 등을 함께 고려해야 합니다.
입력 화면 접근성
24. EditText에는 명확한 레이블 제공
예를 들어 조류 검색 화면의 입력창이 있다고 가정하겠습니다.
<EditText
android:id="@+id/editSearch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/search_bird_hint"
android:inputType="text"
android:imeOptions="actionSearch" /><string name="search_bird_hint">새 이름을 입력하세요</string>힌트는 입력 예시를 제공하는 데 유용합니다.
하지만 입력값이 채워졌을 때도 필드의 의미가 명확해야 하는 화면에서는 별도의 레이블을 사용하는 것이 좋습니다.
25. labelFor 사용하기
<TextView
android:id="@+id/labelBirdName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/bird_name_label"
android:labelFor="@id/editBirdName" />
<EditText
android:id="@+id/editBirdName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" /><string name="bird_name_label">새 이름</string>labelFor는 레이블과 입력 요소 사이의 관계를 접근성 서비스에 전달하는 데 도움이 됩니다.
26. 입력 오류를 명확하게 안내하기
사용자가 필수 입력값을 누락했다고 가정하겠습니다.
단순히 입력창 테두리를 빨간색으로 바꾸는 것만으로는 충분하지 않습니다.
if (birdName.isBlank()) {
binding.editBirdName.error =
getString(
R.string.error_bird_name_required
)
binding.editBirdName.requestFocus()
return
}<string name="error_bird_name_required">새 이름을 입력해 주세요.</string>이렇게 하면 오류 내용을 텍스트로 제공할 수 있습니다.
다만 오류 안내가 실제 TalkBack에서 어떻게 읽히는지는 별도로 테스트해야 합니다.
상태 변경 알림
27. 접근성 Live Region
화면 일부가 동적으로 변경될 때 접근성 서비스에 해당 변경을 알리고 싶을 수 있습니다.
예를 들어 검색 결과 수가 변경되는 경우입니다.
<TextView
android:id="@+id/textResultCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:accessibilityLiveRegion="polite" />binding.textResultCount.text =
getString(
R.string.search_result_count,
resultCount
)<string name="search_result_count">검색 결과 %1$d건</string>polite는 접근성 서비스가 적절한 시점에 변경 내용을 알릴 수 있도록 합니다.
다만 검색어를 입력할 때마다 지나치게 많은 변경을 발생시키면 사용자가 불편할 수 있습니다.
검색 결과가 안정된 시점에 안내하도록 조정하는 것이 좋습니다.
다이얼로그 접근성
28. AlertDialog의 제목과 버튼
다이얼로그에는 사용자가 무엇을 결정해야 하는지 명확하게 표시해야 합니다.
MaterialAlertDialogBuilder(requireContext())
.setTitle("메모 삭제")
.setMessage(
"선택한 메모를 삭제하시겠습니까?"
)
.setNegativeButton(
"취소",
null
)
.setPositiveButton(
"삭제"
) { _, _ ->
deleteMemo()
}
.show()버튼 이름을 단순히 '확인'으로 작성하기보다 '삭제'처럼 실제 동작을 설명하는 것이 좋습니다.
또한 다이얼로그가 표시되었을 때 TalkBack 포커스가 적절한 위치로 이동하는지 확인해야 합니다.
WebView 접근성
29. WebView에서도 접근성이 중요하다
WebView를 사용하는 앱이라면 Android XML뿐 아니라 웹페이지의 HTML 접근성도 고려해야 합니다.
예를 들어 웹페이지의 이미지에는 적절한 alt 속성을 제공해야 합니다.
<img
src="sparrow.jpg"
alt="나뭇가지에 앉아 있는 참새">버튼에는 명확한 이름을 사용해야 합니다.
<button type="button">
검색
</button>또한 HTML 제목 구조, 입력 레이블, 키보드 조작, 포커스 순서 등을 확인해야 합니다.
Android 앱에서 WebView를 사용한다고 해서 웹페이지의 접근성 문제가 자동으로 해결되지는 않습니다.
접근성 자동화 테스트
30. Espresso 접근성 검사
Android UI 테스트에서는 Espresso 접근성 검사 기능을 사용할 수 있습니다.
테스트 의존성을 추가합니다.
androidTestImplementation(
"androidx.test.espresso:espresso-accessibility:<version>"
)테스트 코드에서 다음과 같이 활성화할 수 있습니다.
import androidx.test.espresso.accessibility.AccessibilityChecks
@Before
fun setup() {
AccessibilityChecks.enable()
}접근성 검사는 UI 테스트 중 특정 접근성 문제를 감지하는 데 도움을 줍니다.
하지만 자동화 검사만으로 모든 접근성 문제가 발견되는 것은 아닙니다.
특히 실제 음성 안내의 자연스러움이나 복잡한 화면의 탐색 경험은 수동 테스트가 필요합니다.
31. TalkBack 수동 테스트
TalkBack을 활성화한 상태에서 다음 항목을 확인합니다.
앱 첫 화면에서 포커스가 올바르게 이동하는지
아이콘 버튼의 기능이 읽히는지
좋아요 상태가 전달되는지
RecyclerView 항목 탐색이 자연스러운지
상세 화면으로 이동한 뒤 제목을 파악할 수 있는지
이미지 갤러리의 순서가 전달되는지
다이얼로그의 제목과 버튼이 읽히는지
입력 오류가 안내되는지
하단 내비게이션의 선택 상태를 알 수 있는지
뒤로 가기 이후 포커스가 적절한 위치로 돌아오는지
가능하면 실제 스마트폰에서 TalkBack을 켜고 앱을 처음 사용하는 사람의 입장에서 테스트하는 것이 좋습니다.
32. Accessibility Scanner 활용
Google의 Accessibility Scanner는 Android 화면의 일부 접근성 문제를 확인하는 데 사용할 수 있는 도구입니다.
대표적으로 다음 항목을 점검하는 데 도움이 됩니다.
터치 영역 크기
텍스트 레이블
이미지 설명
색상 대비
하지만 Scanner가 모든 문제를 발견하는 것은 아닙니다.
특히 화면 간 이동 흐름, 동적 상태 변경, TalkBack 음성 안내의 자연스러움은 별도로 확인해야 합니다.
33. 글자 크기 200% 테스트
접근성 테스트에서는 글자 크기를 크게 설정한 상태도 확인하는 것이 좋습니다.
특히 다음 화면에서 문제가 발생하기 쉽습니다.
BottomNavigationView
고정 높이 버튼
가로로 배치된 입력창
RecyclerView 카드
Dialog
날짜 선택 화면
긴 설명이 포함된 상세 화면
텍스트가 잘리는 경우에는 다음 항목을 확인합니다.
layout_height고정 여부wrap_content사용 여부부모 레이아웃의 제약
스크롤 가능 여부
maxLines설정ellipsize설정
특히 중요한 정보가 ellipsize로 잘려 사라지지 않도록 주의해야 합니다.
34. Switch Access와 키보드 조작
접근성은 TalkBack만을 의미하지 않습니다.
Switch Access나 외부 키보드를 사용하는 사용자도 고려해야 합니다.
예를 들어 다음 사항을 확인합니다.
버튼을 순서대로 탐색할 수 있는지
포커스 위치가 시각적으로 구분되는지
모든 주요 기능을 터치 없이 사용할 수 있는지
화면 이동 후 포커스가 예상 가능한 위치에 있는지
특히 커스텀 View나 복잡한 터치 제스처를 사용하는 앱에서는 별도의 대체 조작 방법이 필요할 수 있습니다.
실무 적용 전략
35. 기존 앱의 접근성을 한 번에 개선해야 할까?
이미 출시한 앱이라면 모든 화면을 한 번에 수정하기 어려울 수 있습니다.
이 경우 사용 빈도가 높은 화면부터 개선하는 것이 좋습니다.
예를 들어 조류 도감 앱이라면 다음 순서로 접근할 수 있습니다.
| 우선순위 | 화면 | 주요 점검 항목 |
|---|---|---|
| 1 | 메인 화면 | 하단 메뉴, 탐색 순서 |
| 2 | 검색 화면 | 입력 레이블, 결과 안내 |
| 3 | 목록 화면 | 카드 탐색, 좋아요 버튼 |
| 4 | 상세 화면 | 이미지 설명, 제목 구조 |
| 5 | 메모 화면 | 입력 오류, 저장·삭제 |
| 6 | 설정 화면 | 스위치 상태, 글자 크기 |
기능별로 개선하고 실제 기기에서 검증하는 방식이 효율적입니다.
36. 접근성 문자열을 별도 관리하기
접근성 설명도 일반 문자열과 마찬가지로 strings.xml에서 관리하는 것이 좋습니다.
<resources>
<string name="favorite_add">좋아요 추가</string>
<string name="favorite_remove">좋아요 해제</string>
<string name="search">검색</string>
<string name="bird_photo_description">%1$s 사진</string>
<string name="search_result_count">검색 결과 %1$d건</string>
</resources>이렇게 하면 다국어 지원과 유지보수가 쉬워집니다.
Kotlin 코드에 한국어 문자열을 직접 하드코딩하는 방식은 가급적 피하는 것이 좋습니다.
37. 접근성 개선 전후 비교
예를 들어 좋아요 버튼을 생각해 보겠습니다.
개선 전
<ImageButton
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/ic_favorite" />문제점은 다음과 같습니다.
버튼 기능 설명 없음
터치 영역이 작음
현재 좋아요 상태 전달 부족
개선 후
<ImageButton
android:id="@+id/buttonFavorite"
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_favorite"
android:contentDescription="@string/favorite_add" />그리고 Kotlin에서 상태를 업데이트합니다.
ViewCompat.setStateDescription(
binding.buttonFavorite,
getString(
if (isFavorite) {
R.string.state_selected
} else {
R.string.state_not_selected
}
)
)이렇게 하면 버튼의 기능, 터치 영역, 상태 전달을 함께 개선할 수 있습니다.
38. Android 접근성 체크리스트
아이콘 버튼에 의미 있는 설명 제공
장식용 이미지의 불필요한 접근성 탐색 제거
중요한 이미지에 적절한 설명 제공
중복된 음성 안내 방지
동적 버튼 상태 전달
RecyclerView 탐색 순서 확인
카드 클릭과 내부 버튼 조작 구분
BottomNavigationView 메뉴 이름 확인
ViewPager2 이미지 순서 안내
텍스트 크기에
sp사용글자 크기 확대 시 레이아웃 확인
고정 높이로 인한 텍스트 잘림 방지
충분한 터치 영역 확보
색상만으로 상태를 표현하지 않음
텍스트와 배경의 대비 확인
입력 필드에 명확한 레이블 제공
입력 오류를 텍스트로 안내
동적 상태 안내가 과도하지 않은지 확인
다이얼로그 제목과 버튼 의미 확인
WebView 내부 HTML 접근성 점검
Espresso 접근성 검사 적용
Accessibility Scanner 활용
TalkBack 수동 테스트
글자 크기 확대 테스트
Switch Access 및 키보드 탐색 테스트
39. 마무리
Android 접근성은 특정 사용자만을 위한 부가 기능이 아닙니다.
앱의 정보를 명확하게 전달하고 다양한 입력 방식에 대응하며, 누구나 주요 기능을 사용할 수 있도록 만드는 기본적인 품질 요소입니다.
특히 Kotlin + XML 기반 앱에서는 비교적 작은 수정으로도 접근성을 개선할 수 있습니다.
예를 들어 다음과 같은 작업입니다.
아이콘 버튼에 적절한
contentDescription을 추가합니다.좋아요와 같은 동적 상태를 명확하게 전달합니다.
RecyclerView의 탐색 순서를 확인합니다.
텍스트에는
sp를 사용합니다.글자 크기를 확대해도 레이아웃이 깨지지 않도록 합니다.
터치 영역을 충분히 확보합니다.
색상 외의 방법으로 상태를 표현합니다.
입력 오류를 텍스트로 안내합니다.
자동화 검사와 TalkBack 테스트를 병행합니다.
실제 기기에서 사용 흐름을 검증합니다.
접근성을 개선할 때 가장 중요한 것은 코드에 속성을 추가하는 것 자체가 아닙니다.
사용자가 화면을 보지 않거나 일반적인 터치 조작을 하지 않더라도 앱의 주요 기능을 이해하고 사용할 수 있는지 확인하는 것입니다.
이러한 관점에서 접근성을 점검하면 앱의 완성도와 사용성을 함께 높일 수 있습니다.
참고 자료
Android Developers — Accessibility
https://developer.android.com/guide/topics/ui/accessibilityAndroid Developers — Make Apps More Accessible
https://developer.android.com/guide/topics/ui/accessibility/appsAndroid Developers — Accessibility Principles
https://developer.android.com/guide/topics/ui/accessibility/principlesAndroid Developers — Test Your App's Accessibility
https://developer.android.com/guide/topics/ui/accessibility/testingAndroid Developers — Support Different Font Sizes
https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xmlGoogle Accessibility — TalkBack
https://support.google.com/accessibility/android/answer/6283677W3C — WCAG 2.2 Quick Reference
https://www.w3.org/WAI/WCAG22/quickref/
태그: Android, Kotlin, Accessibility, TalkBack, contentDescription, RecyclerView, ViewPager2, BottomNavigationView, XML, Android 접근성, 글자 크기, 터치 영역, 색상 대비, Espresso, Accessibility Scanner, Android 앱 개발