이 Codelab은 Android Kotlin 기초 과정의 일부입니다. Codelab을 순서대로 진행하면 이 과정의 학습 효과를 극대화할 수 있습니다. 모든 과정 Codelab은 Android Kotlin 기본사항 Codelab 방문 페이지에 나열되어 있습니다.
소개
취미로 개발하든 비즈니스 목적으로 개발하든 최대한 많은 사용자가 사용할 수 있는 앱을 만드는 것이 좋습니다. 이를 달성하기 위한 여러 가지 측면이 있습니다.
- RTL 언어 지원 유럽 및 기타 여러 언어는 왼쪽에서 오른쪽으로 읽으며 이러한 언어에서 유래한 앱은 일반적으로 이러한 언어에 잘 맞도록 설계됩니다. 아랍어와 같이 사용자가 많은 다른 언어는 오른쪽에서 왼쪽으로 읽습니다. 오른쪽에서 왼쪽 (RTL) 언어를 지원하도록 앱을 만들어 잠재고객을 늘리세요.
- 접근성 검사 다른 사람이 앱을 어떻게 경험할지 추측하는 것은 위험한 방법입니다. 접근성 검사기 앱은 추측을 배제하고 앱을 분석하여 접근성을 개선할 수 있는 부분을 파악합니다.
- 콘텐츠 설명과 함께 TalkBack용으로 디자인하세요. 시각장애는 생각보다 흔하며, 시각장애인뿐만 아니라 많은 사용자가 스크린 리더를 사용합니다. 콘텐츠 설명은 사용자가 화면의 요소와 상호작용할 때 스크린 리더가 말하는 문구입니다.
- 야간 모드 지원 많은 시각 장애인 사용자의 경우 화면 색상을 변경하면 대비가 개선되어 앱을 시각적으로 작업하는 데 도움이 됩니다. Android에서는 야간 모드를 쉽게 지원할 수 있으므로 사용자가 기본 화면 색상을 대체할 수 있는 간단한 방법을 제공하기 위해 항상 야간 모드를 지원해야 합니다.
이 Codelab에서는 이러한 각 옵션을 살펴보고 GDG Finder 앱에 지원을 추가합니다.
Android 앱에서 칩을 사용하는 방법도 알아봅니다. 칩을 사용하면 접근성을 유지하면서 앱을 더 흥미롭게 만들 수 있습니다.
기본 요건
다음을 잘 알고 있어야 합니다.
- 활동과 프래그먼트가 있는 앱을 만들고 데이터를 전달하여 프래그먼트 간에 이동하는 방법
- 뷰와 뷰 그룹을 사용하여 사용자 인터페이스를 배치합니다(특히 RecyclerView).
- 권장 아키텍처와 함께
ViewModel를 비롯한 아키텍처 구성요소를 사용하여 잘 구조화되고 효율적인 앱을 만드는 방법 - 데이터 바인딩, 코루틴, 마우스 클릭 처리 방법
- Room 데이터베이스를 사용하여 인터넷에 연결하고 데이터를 로컬로 캐시하는 방법
- 뷰 속성을 설정하는 방법과 XML 리소스 파일로 리소스를 추출하고 XML 리소스 파일에서 리소스를 사용하는 방법을 설명합니다.
- 스타일과 테마를 사용하여 앱의 모양을 맞춤설정하는 방법
- Material 구성요소, 치수 리소스, 맞춤 색상을 사용하는 방법
학습할 내용
- 최대한 많은 사용자가 앱을 사용할 수 있도록 하는 방법
- 오른쪽에서 왼쪽 (RTL) 방향 언어에서 앱이 작동하도록 하는 방법
- 앱의 접근성을 평가하는 방법
- 콘텐츠 설명을 사용하여 스크린 리더에서 앱이 더 잘 작동하도록 하는 방법
- 칩 사용 방법
- 앱이 어두운 모드에서 작동하도록 하는 방법
실습할 내용
- RTL 언어에서 작동하도록 지정된 앱을 평가하고 확장하여 접근성을 개선합니다.
- 앱을 검사하여 접근성을 개선할 수 있는 부분을 확인합니다.
- 이미지에 콘텐츠 설명을 사용합니다.
- 드로어블 사용 방법을 알아봅니다.
- 앱에 야간 모드 사용 기능을 추가합니다.
GDG-finder 스타터 앱은 이 과정에서 지금까지 배운 내용을 기반으로 합니다.
앱은 ConstraintLayout를 사용하여 세 개의 화면을 배치합니다. 두 화면은 Android에서 색상과 텍스트를 탐색하는 데 사용할 레이아웃 파일입니다.
세 번째 화면은 GDG 찾기입니다. GDG(Google Developer 그룹)는 Android를 비롯한 Google 기술에 중점을 두는 개발자 커뮤니티입니다. 전 세계의 GDG는 모임, 콘퍼런스, 스터디 잼, 기타 이벤트를 주최합니다.
이 앱을 개발할 때는 실제 GDG 목록을 사용합니다. 찾기 화면에서는 기기의 위치를 사용하여 GDG를 거리순으로 정렬합니다.
운이 좋게도 거주 지역에 GDG가 있다면 웹사이트를 확인하고 이벤트에 가입할 수 있습니다. GDG 이벤트는 다른 Android 개발자를 만나고 이 과정에 포함되지 않은 업계 권장사항을 배울 수 있는 좋은 방법입니다.
아래 스크린샷은 이 Codelab의 시작부터 끝까지 앱이 어떻게 변경되는지 보여줍니다.
|
|
왼쪽에서 오른쪽 (LTR) 언어와 오른쪽에서 왼쪽 (RTL) 언어의 주요 차이점은 표시되는 콘텐츠의 방향입니다. UI 방향이 LTR에서 RTL로 변경되는 경우 (또는 그 반대) 미러링이라고 합니다. 미러링은 텍스트, 텍스트 필드 아이콘, 레이아웃, 방향이 있는 아이콘 (예: 화살표) 등 화면 대부분에 영향을 미칩니다. 숫자 (시계, 전화번호), 방향이 없는 아이콘 (비행기 모드, Wi-Fi), 재생 컨트롤, 대부분의 차트와 그래프 등은 미러링되지 않습니다.
RTL 텍스트 방향을 사용하는 언어는 전 세계 10억 명 이상의 사용자가 사용합니다. Android 개발자는 전 세계에 있으므로 GDG Finder 앱은 RTL 언어를 지원해야 합니다.
1단계: RTL 지원 추가
이 단계에서는 GDG Finder 앱이 RTL 언어와 호환되도록 합니다.
- 이 Codelab의 시작 앱인 GDGFinderMaterial 앱을 다운로드하여 실행하거나 이전 Codelab의 최종 코드에서 계속 진행합니다.
- Android 매니페스트를 엽니다.
<application>섹션에 다음 코드를 추가하여 앱이 RTL을 지원한다고 지정합니다.
<application
...
android:supportsRtl="true">- Design 탭에서 activity_main.xml을 엽니다.
- 미리보기 언어 드롭다운 메뉴에서 오른쪽에서 왼쪽으로 미리보기를 선택합니다. (이 메뉴가 표시되지 않으면 창을 넓히거나 속성 창을 닫아 메뉴를 표시합니다.)

- 미리보기에서 'GDG Finder' 헤더가 오른쪽으로 이동하고 나머지 화면은 거의 동일하게 유지되는 것을 확인할 수 있습니다. 전반적으로 이 화면은 괜찮습니다. 하지만 이제 텍스트 뷰의 정렬이 잘못되었습니다. 오른쪽이 아닌 왼쪽에 정렬되어 있기 때문입니다.

- 기기에서 이 기능을 사용하려면 기기 또는 에뮬레이터 설정의 개발자 옵션에서 RTL 레이아웃 강제 적용을 선택합니다. (개발자 옵션을 사용 설정해야 하는 경우 빌드 번호를 찾아 개발자임을 나타내는 토스트가 표시될 때까지 클릭합니다. 이는 기기 및 Android 시스템 버전에 따라 다릅니다.)

- 앱을 실행하고 기기에서 기본 화면이 미리보기와 동일하게 표시되는지 확인합니다. 이제 FAB가 왼쪽으로 전환되고 햄버거 메뉴가 오른쪽으로 전환됩니다.
- 앱에서 탐색 창을 열고 검색 화면으로 이동합니다. 아래와 같이 아이콘은 여전히 왼쪽에 있으며 텍스트는 표시되지 않습니다. 텍스트가 아이콘의 왼쪽에 있어 화면에 표시되지 않습니다. 이는 코드가 뷰 속성과 레이아웃 제약 조건에서 왼쪽/오른쪽 화면 참조를 사용하기 때문입니다.
|
|
2단계: 왼쪽 및 오른쪽 대신 시작 및 종료 사용
텍스트 방향이 바뀌더라도 화면의 '왼쪽'과 '오른쪽'(화면을 바라볼 때)은 바뀌지 않습니다. 예를 들어 layout_constraintLeft_toLeftOf는 항상 요소의 왼쪽을 화면의 왼쪽에 제한합니다. 앱의 경우 위 스크린샷에 표시된 것처럼 RTL 언어에서 텍스트가 화면에 표시되지 않습니다.
이 문제를 해결하려면 '왼쪽' 및 '오른쪽' 대신 Start 및 End 용어를 사용하세요. 이 용어는 현재 언어의 텍스트 방향에 맞게 텍스트의 시작과 끝을 설정하므로 여백과 레이아웃이 화면의 올바른 영역에 있습니다.
Openlist_item.xmlLeft및Right에 대한 참조를Start및End에 대한 참조로 바꿉니다.
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintStart_toEndOf="@+id/gdg_image"
app:layout_constraintEnd_toEndOf="parent"ImageView의layout_marginLeft을layout_marginStart로 바꿉니다. 이렇게 하면 아이콘이 화면 가장자리에서 멀어지도록 여백이 올바른 위치로 이동합니다.
<ImageView
android:layout_marginStart="
?fragment_gdg_list.xml를 엽니다. 미리보기 창에서 GDG 목록을 확인합니다. 아이콘이 미러링되어 여전히 잘못된 방향을 가리키고 있습니다. 아이콘이 미러링되지 않은 경우 오른쪽에서 왼쪽으로 미리보기를 계속 보고 있는지 확인하세요. Material Design 가이드라인에 따라 아이콘은 미러링하면 안 됩니다.- res/drawable/ic_gdg.xml을 엽니다.
- XML 코드의 첫 번째 줄에서
android:autoMirrored="true"를 찾아 삭제하여 미러링을 사용 중지합니다. - 미리보기를 확인하거나 앱을 다시 실행하고 GDG 검색 화면을 엽니다. 이제 레이아웃이 수정되었습니다.

3단계: Android 스튜디오에서 자동으로 작업하도록 허용
이전 연습에서는 RTL 언어를 지원하기 위한 첫 단계를 진행했습니다. 다행히 Android 스튜디오는 앱을 스캔하고 많은 기본사항을 설정할 수 있습니다.
- list_item.xml의
TextView에서layout_marginStart을 다시layout_marginLeft로 변경하여 스캐너가 찾을 수 있도록 합니다.
<TextView
android:layout_marginLeft="@dimen/spacing_normal"- Android 스튜디오에서 Refactor > Add RTL support where possible을 선택하고 매니페스트와 레이아웃 파일을 업데이트하여 시작 및 종료 속성을 사용하는 체크박스를 선택합니다.

- 리팩터링 미리보기 창에서 app 폴더를 찾아 모든 세부정보가 표시될 때까지 펼칩니다.
- 앱 폴더 아래에 방금 변경한
layout_marginLeft가 리팩터링할 코드로 표시됩니다.

- 미리보기에는 시스템 파일과 라이브러리 파일도 표시됩니다. layout, layout-watch-v20, app에 속하지 않는 다른 폴더를 마우스 오른쪽 버튼으로 클릭하고 컨텍스트 메뉴에서 제외를 선택합니다.

- 지금 리팩터링을 진행하세요. (시스템 파일에 관한 팝업이 표시되면 앱 코드에 포함되지 않은 모든 폴더를 제외했는지 확인하세요.)
layout_marginLeft이 다시layout_marginStart으로 변경되었습니다.
3단계: 언어 폴더 탐색
지금까지는 앱에 사용되는 기본 언어의 방향만 변경했습니다. 프로덕션 앱의 경우 strings.xml 파일을 번역가에게 보내 새 언어로 번역해야 합니다. 이 Codelab에서는 앱이 스페인어로 된 strings.xml 파일을 제공합니다 (Google 번역을 사용하여 번역을 생성했으므로 완벽하지는 않습니다).
- Android 스튜디오에서 프로젝트 뷰를 프로젝트 파일로 전환합니다.
- res 폴더를 펼치면 res/values 및 res/values-es 폴더가 표시됩니다. 폴더 이름의 'es'는 스페인어의 언어 코드입니다. values-'언어 코드' 폴더에는 지원되는 각 언어의 값이 포함되어 있습니다. 확장자가 없는 values 폴더에는 그렇지 않은 경우 적용되는 기본 리소스가 포함되어 있습니다.

- values-es에서 strings.xml을 열면 모든 문자열이 스페인어로 되어 있습니다.
- Android 스튜디오의 Design 탭에서
activity_main.xml을 엽니다. - 미리보기 언어 드롭다운에서 스페인어를 선택합니다. 이제 텍스트가 스페인어로 표시됩니다.

- [선택사항] RTL 언어에 능숙한 경우 해당 언어로 values 폴더와 strings.xml을 만들고 기기에서 어떻게 표시되는지 테스트합니다.
- [선택사항] 기기의 언어 설정을 변경하고 앱을 실행합니다. 기기를 읽을 수 없는 언어로 변경하지 마세요. 되돌리기가 다소 어려워집니다.
이전 작업에서는 앱을 수동으로 변경한 다음 Android 스튜디오를 사용하여 추가로 적용할 RTL 개선사항을 확인했습니다.
접근성 검사기 앱은 앱의 접근성을 높이는 데 가장 유용한 도구입니다. 타겟 기기에서 앱을 검사하고 터치 타겟을 크게 만들고, 대비를 높이고, 이미지 설명을 제공하여 앱의 접근성을 높이는 등의 개선사항을 제안합니다. 접근성 검사기는 Google에서 제작했으며 Play 스토어에서 설치할 수 있습니다.
1단계: 접근성 검사기 설치 및 실행
- Play 스토어를 열고 필요한 경우 로그인합니다. 실제 기기나 에뮬레이터에서 이 작업을 실행할 수 있습니다. 이 Codelab에서는 에뮬레이터를 사용합니다.
- Play 스토어에서 Google LLC의 접근성 검사기를 검색합니다. 스캔에는 많은 권한이 필요하므로 Google에서 발행한 올바른 앱을 다운로드해야 합니다.

- 에뮬레이터에 스캐너를 설치합니다.
- 설치가 완료되면 열기를 클릭합니다.
- 시작하기를 클릭합니다.
- 확인을 클릭하여 설정에서 접근성 검사기 설정을 시작합니다.

- 접근성 검사기를 클릭하여 기기의 접근성 설정으로 이동합니다.

- 서비스 사용을 클릭하여 사용 설정합니다.

- 화면에 표시된 안내를 따르고 모든 권한을 부여합니다.
- 그런 다음 확인을 클릭하고 홈 화면으로 돌아갑니다. 화면에 체크표시가 있는 파란색 버튼이 표시될 수 있습니다. 이 버튼을 클릭하면 포그라운드에 있는 앱의 테스트가 트리거됩니다. 버튼을 드래그하여 위치를 변경할 수 있습니다. 이 버튼은 앱 위에 표시되므로 언제든지 테스트를 트리거할 수 있습니다.

- 앱을 열거나 실행합니다.
- 파란색 버튼을 클릭하고 추가 보안 경고 및 권한을 수락합니다.
접근성 검사기 아이콘을 처음 클릭하면 앱에서 화면에 표시되는 모든 항목을 가져올 수 있는 권한을 요청합니다. 매우 무서운 권한처럼 보이지만 실제로도 그렇습니다.
이러한 권한은 앱이 이메일을 읽거나 은행 계정 정보를 가져갈 수 있으므로 거의 부여하지 않는 것이 좋습니다. 하지만 접근성 스캐너가 작동하려면 사용자가 앱을 사용하는 방식으로 앱을 검사해야 합니다. 따라서 이 권한이 필요합니다.
- 파란색 버튼을 클릭하고 분석이 완료될 때까지 기다립니다. 아래 스크린샷과 같이 제목과 FAB가 빨간색으로 표시됩니다. 이 화면에 접근성 개선을 위한 제안이 두 개 표시됩니다.

- GDG Finder를 둘러싼 상자를 클릭합니다. 그러면 아래와 같이 이미지 대비에 문제가 있음을 나타내는 추가 정보가 포함된 창이 열립니다.
- 이미지 대비 정보를 펼치면 도구에서 해결 방법을 제안합니다.
- 오른쪽의 화살표를 클릭하여 다음 항목의 정보를 확인합니다.
|
|
- 앱에서 GDG 신청 화면으로 이동하여 접근성 검사기 앱으로 스캔합니다. 그러면 왼쪽 아래와 같이 여러 제안이 표시됩니다. 정확히 말하면 12개입니다. 공정성을 위해 유사한 상품의 중복 항목도 포함되어 있습니다.
- 하단 툴바에서 '스택'
아이콘을 클릭하여 모든 추천 목록을 확인합니다(오른쪽 스크린샷 참고). 이 Codelab에서는 이러한 모든 문제를 해결합니다.
|
|
Google의 앱 모음인 Android 접근성 도구 모음에는 앱의 접근성을 높이는 데 도움이 되는 도구가 포함되어 있습니다. 여기에는 TalkBack과 같은 도구가 포함되어 있습니다. TalkBack은 청각, 촉각, 음성 피드백을 제공하는 스크린 리더로, 사용자가 눈을 사용하지 않고도 기기에서 콘텐츠를 탐색하고 소비할 수 있습니다.
TalkBack은 시각장애인뿐만 아니라 다양한 시각 장애가 있는 많은 사용자가 사용하고 있습니다. 눈을 쉬고 싶은 사람도 마찬가지입니다.
따라서 접근성은 모두를 위한 것입니다. 이 작업에서는 TalkBack을 사용해 보고 TalkBack과 잘 작동하도록 앱을 업데이트합니다.
1단계: 접근성 도구 모음 설치 및 실행
TalkBack은 많은 실제 기기에 사전 설치되어 있지만 에뮬레이터에서는 설치해야 합니다.
- Play 스토어를 엽니다.
- 접근성 도구 모음을 찾습니다. Google에서 제공하는 올바른 앱인지 확인합니다.
- 설치되어 있지 않으면 접근성 모음을 설치합니다.
- 기기에서 TalkBack을 사용 설정하려면 설정 > 접근성으로 이동하여 서비스 사용을 선택하여 TalkBack을 사용 설정합니다. 접근성 스캐너와 마찬가지로 TalkBack은 화면의 콘텐츠를 읽기 위해 권한이 필요합니다. 권한 요청을 수락하면 TalkBack에서 TalkBack을 효과적으로 사용하는 방법을 알려주는 튜토리얼 목록으로 환영합니다.
- 여기서 일시중지하고 가이드를 살펴보세요. 완료되면 TalkBack을 다시 사용 중지하는 방법을 알아두는 것이 좋습니다.
- 튜토리얼을 종료하려면 뒤로 버튼을 클릭하여 선택한 다음 화면의 아무 곳이나 두 번 탭합니다.
- TalkBack을 사용하여 GDG Finder 앱을 탐색합니다. TalkBack에서 화면이나 컨트롤에 관한 유용한 정보를 제공하지 않는 위치를 확인합니다. 다음 연습에서 이 문제를 해결합니다.
2단계: 콘텐츠 설명 추가
콘텐츠 설명어는 조회수의 의미를 설명하는 설명 라벨입니다. 대부분의 뷰에는 콘텐츠 설명이 있어야 합니다.
- GDG Finder 앱이 실행되고 TalkBack이 사용 설정된 상태에서 GDG 운영 신청 화면으로 이동합니다.
- 기본 이미지를 탭해도 아무 일도 일어나지 않습니다.
- add_gdg_fragment.xml을 엽니다.
ImageView에서 아래와 같이 콘텐츠 설명어 속성을 추가합니다.stage_image_description문자열은 strings.xml에 제공됩니다.
android:contentDescription="@string/stage_image_description"- 앱을 실행합니다.
- GDG 운영 신청으로 이동하여 이미지를 클릭합니다. 이제 이미지에 대한 간단한 설명이 들립니다.
- [선택사항] 이 앱의 다른 이미지에 콘텐츠 설명을 추가합니다. 프로덕션 앱에서는 모든 이미지에 콘텐츠 설명이 있어야 합니다.
3단계: 수정 가능한 텍스트 필드에 힌트 추가
EditText과 같은 수정 가능한 요소의 경우 XML에서 android:hint을 사용하여 사용자가 입력해야 하는 내용을 파악할 수 있습니다. 힌트는 입력 필드의 기본 텍스트이므로 항상 UI에 표시됩니다.
- add_gdg_fragment.xml에 계속 있습니다.
- 아래 코드를 참고하여 콘텐츠 설명과 힌트를 추가합니다.
textViewIntro에 추가합니다.
android:contentDescription="@string/add_gdg"각각 수정 텍스트에 추가합니다.
android:hint="@string/your_name_label"
android:hint="@string/email_label"
android:hint="@string/city_label"
android:hint="@string/country_label"
android:hint="@string/region_label"labelTextWhy에 콘텐츠 설명을 추가합니다.
android:contentDescription="@string/motivation" EditTextWhy에 힌트를 추가합니다. 수정 상자에 라벨을 지정한 후 라벨에 콘텐츠 설명을 추가하고 상자에 힌트를 추가합니다.
android:hint="@string/enter_motivation"- 제출 버튼에 콘텐츠 설명을 추가합니다. 모든 버튼에는 버튼을 누르면 발생하는 상황에 관한 설명이 있어야 합니다.
android:contentDescription="@string/submit_button_description"- TalkBack을 사용 설정한 상태로 앱을 실행하고 GDG 운영을 신청하는 양식을 작성하세요.
4단계: 콘텐츠 그룹 만들기
TalkBack에서 그룹으로 처리해야 하는 UI 컨트롤의 경우 콘텐츠 그룹화를 사용할 수 있습니다. 함께 그룹화된 관련 콘텐츠는 함께 발표됩니다. 그러면 지원 기술 사용자가 화면의 모든 정보를 확인하기 위해 스와이프하거나, 스캔하거나, 기다리는 빈도가 줄어듭니다. 이는 화면에 컨트롤이 표시되는 방식에는 영향을 미치지 않습니다.
UI 구성요소를 그룹화하려면 LinearLayout과 같은 ViewGroup로 래핑하세요. GDG Finder 앱에서 labelTextWhy 및 editTextWhy 요소는 의미상 함께 속하므로 그룹화하기에 적합합니다.
- add_gdg_fragment.xml을 엽니다.
LabelTextWhy및EditTextWhy주위에LinearLayout를 래핑하여 콘텐츠 그룹을 만듭니다. 아래 코드를 복사하여 붙여넣습니다. 이LinearLayout에는 이미 필요한 스타일이 일부 포함되어 있습니다. (button가LinearLayout외부에 있는지 확인하세요.)
<LinearLayout android:id="@+id/contentGroup" android:layout_width="match_parent"
android:layout_height="wrap_content" android:focusable="true"
app:layout_constraintTop_toBottomOf="@id/EditTextRegion"
android:orientation="vertical" app:layout_constraintStart_toStartOf="@+id/EditTextRegion"
app:layout_constraintEnd_toEndOf="@+id/EditTextRegion"
android:layout_marginTop="16dp" app:layout_constraintBottom_toTopOf="@+id/button"
android:layout_marginBottom="8dp">
<!-- label and edit text here –>
<LinearLayout/>- Code > Reformat code를 선택하여 모든 코드를 적절하게 들여씁니다.
labelTextWhy및editTextWhy에서 모든 레이아웃 여백을 삭제합니다.labelTextWhy에서layout_constraintTop_toTopOf제약 조건을contentGroup로 변경합니다.
app:layout_constraintTop_toTopOf="@+id/contentGroup" />editTextWhy에서layout_constraintBottom_toBottomOf제약 조건을contentGroup로 변경합니다.
app:layout_constraintBottom_toBottomOf="@+id/contentGroup"EditTextRegion와Button을contentGroup로 제한하여 오류를 없앱니다.
app:layout_constraintBottom_toTopOf="@+id/contentGroup"LinearLayout에 여백을 추가합니다. 원하는 경우 이 여백을 측정기준으로 추출합니다.
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"도움이 필요하면 솔루션 코드의 add_gdg_fragment.xml와 코드를 비교하세요.
- 앱을 실행하고 TalkBack으로 GDG 실행 신청 화면을 탐색합니다.
5단계: 라이브 리전 추가
현재 제출 버튼의 라벨은 확인입니다. 양식을 제출하기 전에는 버튼에 하나의 라벨과 설명이 있고 사용자가 클릭하고 양식이 제출된 후에는 다른 라벨과 콘텐츠 설명으로 동적으로 변경되는 것이 좋습니다. 라이브 리전을 사용하여 이 작업을 수행할 수 있습니다.
라이브 영역은 뷰가 변경될 때 사용자에게 알림을 보내야 하는지 접근성 서비스에 나타냅니다. 예를 들어 사용자에게 잘못된 비밀번호나 네트워크 오류를 알리는 것은 앱의 접근성을 높이는 좋은 방법입니다. 이 예에서는 간단하게 제출 버튼의 상태가 변경될 때 사용자에게 알립니다.
- add_gdg_fragment.xml을 엽니다.
- 제공된
submit문자열 리소스를 사용하여 버튼의 텍스트 할당을 Submit으로 변경합니다.
android:text="@string/submit"android:accessibilityLiveRegion속성을 설정하여 버튼에 라이브 리전을 추가합니다. 입력할 때 값에 사용할 수 있는 옵션이 여러 개 표시됩니다. 변경사항의 중요도에 따라 사용자를 중단할지 여부를 선택할 수 있습니다. 'assertive' 값을 사용하면 접근성 서비스가 진행 중인 음성 안내를 중단하고 이 뷰의 변경사항을 즉시 알립니다. 값을 'none'으로 설정하면 변경사항이 공지되지 않습니다. '공손함'으로 설정하면 접근성 서비스가 변경사항을 알리지만 순서를 기다립니다. 값을 'polite'로 설정합니다.

android:accessibilityLiveRegion="polite"- add 패키지에서 AddGdgFragment.kt를 엽니다.
showSnackBarEventObserver내에서SnackBar표시가 완료된 후 버튼의 새 콘텐츠 설명과 텍스트를 설정합니다.
binding.button.contentDescription=getString(R.string.submitted)
binding.button.text=getString(R.string.done)- 앱을 실행하고 버튼을 클릭합니다. 안타깝게도 버튼과 글꼴이 너무 작습니다.
6단계: 버튼 스타일 수정
- add_gdg_fragment.xml에서 버튼의
width및height를wrap_content로 변경하여 전체 라벨이 표시되고 버튼이 적절한 크기가 되도록 합니다.
android:layout_width="wrap_content"
android:layout_height="wrap_content"- 앱에서 더 나은 테마 스타일을 사용하도록 버튼에서
backgroundTint,textColor,textSize속성을 삭제합니다. textViewIntro에서textColor속성을 삭제합니다. 테마 색상은 대비가 적절해야 합니다.- 앱을 실행합니다. 훨씬 더 유용한 Submit 버튼이 표시됩니다. 제출을 클릭하면 완료로 변경됩니다.
|
|
칩은 속성, 텍스트, 항목 또는 작업을 나타내는 간단한 요소입니다. 사용자가 정보를 입력하거나, 선택사항을 선택하거나, 콘텐츠를 필터링하거나, 작업을 트리거할 수 있습니다.
Chip 위젯은 모든 레이아웃 및 그리기 로직이 포함된 ChipDrawable을 감싸는 얇은 뷰 래퍼입니다. 추가 로직은 터치, 마우스, 키보드, 접근성 탐색을 지원하기 위해 존재합니다. 기본 칩과 닫기 아이콘은 별도의 논리적 하위 뷰로 간주되며 자체 탐색 동작과 상태를 포함합니다.

칩은 드로어블을 사용합니다. Android 드로어블을 사용하면 화면에 이미지, 도형, 애니메이션을 그릴 수 있으며, 고정된 크기이거나 동적으로 크기를 조정할 수 있습니다. GDG 앱의 이미지와 같은 이미지를 드로어블로 사용할 수 있습니다. 벡터 드로잉을 사용하면 상상할 수 있는 모든 것을 그릴 수 있습니다. 이 Codelab에서는 다루지 않지만 9패치 드로어블이라는 크기 조절 가능한 드로어블도 있습니다. drawable/ic_gdg.xml의 GDG 로고는 또 다른 드로어블입니다.
드로어블은 뷰가 아니므로 ConstraintLayout 내부에 직접 드로어블을 배치할 수 없습니다. ImageView 내부에 배치해야 합니다. 드로어블을 사용하여 텍스트 뷰나 버튼의 배경을 제공할 수도 있으며 배경은 텍스트 뒤에 그려집니다.
1단계: GDG 목록에 칩 추가
아래의 선택된 칩은 드로어블 3개를 사용합니다. 배경과 체크표시는 각각 드로어블입니다. 칩을 터치하면 물결 효과가 생성됩니다. 이는 상태 변경에 따라 물결 효과를 표시하는 특수 RippleDrawable을 사용하여 실행됩니다.

이 작업에서는 GDG 목록에 칩을 추가하고 칩이 선택되면 상태가 변경되도록 합니다. 이 연습에서는 검색 화면 상단에 칩이라는 버튼 행을 추가합니다. 각 버튼은 사용자가 선택한 지역의 결과만 수신하도록 GDG 목록을 필터링합니다. 버튼을 선택하면 버튼의 배경이 변경되고 체크표시가 표시됩니다.
- fragment_gdg_list.xml을 엽니다.
HorizontalScrollView.내부에com.google.android.material.chip.ChipGroup를 만듭니다. 모든 칩이 수평으로 스크롤 가능한 한 줄에 정렬되도록singleLine속성을true로 설정합니다. 그룹에서 한 번에 하나의 칩만 선택할 수 있도록singleSelection속성을true로 설정합니다. 코드는 다음과 같습니다.
<com.google.android.material.chip.ChipGroup
android:id="@+id/region_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:singleSelection="true"
android:padding="@dimen/spacing_normal"/>- layout 폴더에서 하나의
Chip의 레이아웃을 정의하는 region.xml이라는 새 레이아웃 리소스 파일을 만듭니다. - region.xml에서 모든 코드를 아래에 나온 하나의
Chip레이아웃으로 바꿉니다. 이Chip은 Material 구성요소입니다.app:checkedIconVisible속성을 설정하면 체크표시가 표시됩니다.selected_highlight색상이 누락되어 오류가 발생합니다.
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.chip.Chip
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Widget.MaterialComponents.Chip.Choice"
app:chipBackgroundColor="@color/selected_highlight"
app:checkedIconVisible="true"
tools:checked="true"/>- 누락된
selected_highlight색상을 만들려면selected_highlight에 커서를 놓고 의도 메뉴를 불러온 다음 선택한 강조 표시의 색상 리소스 만들기를 선택합니다. 기본 옵션이 적절하므로 OK를 클릭합니다. 파일은 res/color 폴더에 생성됩니다. - res/color/selected_highlight.xml을 엽니다.
<selector>로 인코딩된 이 색상 상태 목록에서는 다양한 상태에 다양한 색상을 제공할 수 있습니다. 각 상태와 연결된 색상은<item>로 인코딩됩니다. 이러한 색상에 대한 자세한 내용은 색상 테마를 참고하세요.
<selector>내부에 기본 색상colorOnSurface이 있는 항목을 상태 목록에 추가합니다. 주 목록에서는 항상 모든 주를 포함하는 것이 중요합니다. 이를 위한 한 가지 방법은 기본 색상을 사용하는 것입니다.
<item android:alpha="0.18" android:color="?attr/colorOnSurface"/>- 기본 색상 위에 색상이
colorPrimaryVariant인item를 추가하고 선택된 상태가true일 때만 사용하도록 제한합니다. 상태 목록은 case 문과 같이 위에서 아래로 처리됩니다. 일치하는 상태가 없으면 기본 상태가 적용됩니다.
<item android:color="?attr/colorPrimaryVariant"
android:state_selected="true" />2단계: 칩 행 표시
GDG 앱은 GDG가 있는 지역을 보여주는 칩 목록을 만듭니다. 칩을 선택하면 앱에서 해당 지역의 GDG 결과만 표시하도록 결과를 필터링합니다.
- search 패키지에서 GdgListFragment.kt를 엽니다.
onCreateView()에서return문 바로 위에viewModel.regionList의 관찰자를 추가하고onChanged()를 재정의합니다. 뷰 모델에서 제공하는 지역 목록이 변경되면 칩을 다시 만들어야 합니다. 제공된data가null인 경우 즉시 반환하는 문을 추가합니다.
viewModel.regionList.observe(viewLifecycleOwner, object: Observer<List<String>> {
override fun onChanged(data: List<String>?) {
data ?: return
}
})onChanged()내에서 null 테스트 아래에binding.regionList을chipGroup라는 새 변수에 할당하여regionList를 캐시합니다.
val chipGroup = binding.regionList- 아래에서
chipGroup.context에서 칩을 확장하기 위한 새layoutInflator를 만듭니다.
val inflator = LayoutInflater.from(chipGroup.context)- 데이터 바인딩 오류를 없애려면 프로젝트를 정리하고 다시 빌드하세요.
이제 인플레이터 아래에 실제 칩을 만들 수 있습니다. regionList의 각 지역에 하나씩 만듭니다.
- 모든 칩을 보유하는
children변수를 만듭니다. 전달된data에 매핑 함수를 할당하여 각 칩을 만들고 반환합니다.
val children = data.map {} - 맵 람다 내에서 각
regionName에 대해 칩을 만들고 확장합니다. 완성된 코드는 아래와 같습니다.
val children = data.map {
val children = data.map { regionName ->
val chip = inflator.inflate(R.layout.region, chipGroup, false) as Chip
chip.text = regionName
chip.tag = regionName
// TODO: Click listener goes here.
chip
}
}- 람다 내에서
chip를 반환하기 직전에 클릭 리스너를 추가합니다.chip을 클릭하면 상태를checked로 설정합니다.viewModel에서onFilterChanged()를 호출합니다. 그러면 이 필터의 결과를 가져오는 일련의 이벤트가 트리거됩니다.
chip.setOnCheckedChangeListener { button, isChecked ->
viewModel.onFilterChanged(button.tag as String, isChecked)
}- 람다 끝에서
chipGroup에서 현재 뷰를 모두 삭제한 다음children의 칩을 모두chipGroup에 추가합니다. (칩은 업데이트할 수 없으므로chipGroup의 콘텐츠를 삭제하고 다시 만들어야 합니다.)
chipGroup.removeAllViews()
for (chip in children) {
chipGroup.addView(chip)
}완성된 옵저버는 다음과 같습니다.
override fun onChanged(data: List<String>?) {
data ?: return
val chipGroup = binding.regionList
val inflator = LayoutInflater.from(chipGroup.context)
val children = data.map { regionName ->
val chip = inflator.inflate(R.layout.region, chipGroup, false) as Chip
chip.text = regionName
chip.tag = regionName
chip.setOnCheckedChangeListener { button, isChecked ->
viewModel.onFilterChanged(button.tag as String, isChecked)
}
chip
}
chipGroup.removeAllViews()
for (chip in children) {
chipGroup.addView(chip)
}
}
})
- 앱을 실행하고 GDGS를 검색하여 검색 화면을 열어 새 칩을 사용합니다. 각 칩을 클릭하면 앱에 아래에 필터 그룹이 표시됩니다.

야간 모드를 사용하면 기기 설정이 야간 모드를 사용하도록 설정된 경우와 같이 앱이 색상을 어두운 테마로 변경할 수 있습니다. 야간 모드에서는 앱이 기본 밝은 배경을 어둡게 변경하고 다른 모든 화면 요소를 그에 따라 변경합니다.
1단계: 야간 모드 사용 설정
앱에 어두운 테마를 제공하려면 테마를 Light 테마에서 DayNight이라는 테마로 변경합니다. DayNight 테마는 모드에 따라 밝게 또는 어둡게 표시됩니다.
styles.xml,에서AppTheme상위 테마를Light에서DayNight로 변경합니다.
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">MainActivity의onCreate()메서드에서AppCompatDelegate.setDefaultNightMode()를 호출하여 프로그래매틱 방식으로 어두운 테마를 사용 설정합니다.
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)- 앱을 실행하고 어두운 테마로 전환되었는지 확인합니다.

2단계: 자체 어두운 테마 색상 팔레트 생성
어두운 테마를 맞춤설정하려면 어두운 테마에 사용할 -night 한정자를 사용하여 폴더를 만듭니다. 예를 들어 values-night라는 폴더를 만들어 야간 모드에서 특정 색상을 사용할 수 있습니다.
- material.io 색상 선택 도구를 방문하여 야간 테마 색상 팔레트를 만듭니다. 예를 들어 어두운 파란색을 기반으로 할 수 있습니다.
- colors.xml 파일을 생성하고 다운로드합니다.
- 프로젝트 파일 뷰로 전환하여 프로젝트의 모든 폴더를 나열합니다.
- res 폴더를 찾아 펼칩니다.
- res/values-night 리소스 폴더를 만듭니다.
- 새 colors.xml 파일을 res/values-night 리소스 폴더에 추가합니다.
- 야간 모드가 사용 설정된 상태로 앱을 실행하면 앱이 res/values-night에 정의된 새 색상을 사용합니다. 칩이 새로운 보조 색상을 사용합니다.

Android 스튜디오 프로젝트: GDGFinderFinal
RTL 언어 지원
- Android 매니페스트에서
android:supportsRtl="true"를 설정합니다. - 에뮬레이터에서 RTL을 미리 볼 수 있으며, 자신의 언어를 사용하여 화면 레이아웃을 확인할 수 있습니다. 기기 또는 에뮬레이터에서 설정을 열고 개발자 옵션에서 RTL 레이아웃 강제 적용을 선택합니다.
Left및Right에 대한 참조를Start및End에 대한 참조로 바꿉니다.android:autoMirrored="true"를 삭제하여 드로어블의 미러링을 사용 중지합니다.- 리팩터링 > 가능한 경우 RTL 지원 추가 를 선택하여 Android 스튜디오가 작업을 대신하도록 합니다.
- values-'언어 코드' 폴더를 사용하여 언어별 리소스를 저장합니다.
접근성 검사
- Play 스토어에서 Google LLC의 접근성 검사기를 다운로드하고 실행하여 개선할 화면 요소를 검사합니다.
콘텐츠 설명과 함께 TalkBack용으로 디자인하기
- Google의 Android 접근성 도구 모음을 설치합니다. 여기에는 TalkBack이 포함되어 있습니다.
- 모든 UI 요소에 콘텐츠 설명을 추가합니다. 예를 들면 다음과 같습니다.
android:contentDescription="@string/stage_image_description" EditText와 같은 수정 가능한 요소의 경우 XML에서android:hint속성을 사용하여 입력할 내용에 관한 힌트를 사용자에게 제공합니다.- 관련 요소를 뷰 그룹으로 래핑하여 콘텐츠 그룹을 만듭니다.
android:accessibilityLiveRegion를 사용하여 사용자에게 추가 의견을 제공하는 라이브 리전을 만듭니다.
칩을 사용하여 필터 구현
- 칩은 속성, 텍스트, 항목 또는 작업을 나타내는 간단한 요소입니다.
- 칩 그룹을 만들려면
com.google.android.material.chip.ChipGroup를 사용합니다. - 하나의
com.google.android.material.chip.Chip레이아웃을 정의합니다. - 칩의 색상을 변경하려면 상태가 있는 색상으로
<selector>로 색상 상태 목록을 제공하세요.<item android:color="?attr/colorPrimaryVariant"
android:state_selected="true" /> - 뷰 모델의 데이터에 관찰자를 추가하여 칩을 라이브 데이터에 바인딩합니다.
- 칩을 표시하려면 칩 그룹의 인플레이터를 만듭니다.
LayoutInflater.from(chipGroup.context) - 칩을 만들고, 원하는 작업을 트리거하는 클릭 리스너를 추가하고, 칩 그룹에 칩을 추가합니다.
어두운 모드 지원
DayNightAppTheme을 사용하여 어두운 모드를 지원합니다.- 어두운 모드는 프로그래밍 방식으로 설정할 수 있습니다.
AppCompatDelegate.setDefaultNightMode() - res/values-night 리소스 폴더를 만들어 다크 모드의 맞춤 색상과 값을 제공합니다.
Android 개발자 문서:
LayoutDirection(RTL)- 양방향성
- 접근성 검사기 시작하기
- Talkback
- TalkBack 동작
- 드로어블 개요 문서
- 콘텐츠 설명어
- 콘텐츠 분류
- 라이브 영역
- NinePatch 드로어블
- Draw 9-patch 도구
- 칩
ChipGroup- 어두운 테마
- 색상 테마 설정
- 색상 도구
- 드로어블 그래픽 애니메이션화
기타 자료:
- Kotlin을 사용하여 Android 앱 개발(Udacity 과정)
- 프로그래머를 위한 Kotlin 부트캠프 (Udacity 과정)
- 프로그래머를 위한 Kotlin 부트캠프 Codelab
이 섹션에는 강사가 진행하는 과정의 일부로 이 Codelab을 진행하는 학생에게 출제할 수 있는 과제가 나열되어 있습니다. 다음 작업은 강사가 결정합니다.
- 필요한 경우 과제를 할당합니다.
- 과제 제출 방법을 학생에게 알립니다.
- 과제를 채점합니다.
강사는 이러한 추천을 원하는 만큼 사용할 수 있으며 적절하다고 생각되는 다른 과제를 출제해도 됩니다.
이 Codelab을 직접 진행하는 경우 이러한 과제를 자유롭게 사용하여 배운 내용을 테스트해 보세요.
질문 1
다음 중 RTL 언어를 지원하는 데 반드시 필요한 것은 무엇인가요?
▢ 속성의 Left 및 Right을 Start 및 End로 바꿉니다.
▢ RTL 언어로 전환
▢ 모든 아이콘이 android:autoMirrored="true"를 사용해야 합니다.
▢ 콘텐츠 설명 제공
질문 2
다음 중 대부분의 Android 기기에 내장된 접근성 도구는 무엇인가요?
▢ TalkBack
▢ 접근성 검사기
▢ Android 스튜디오에서 Refactor > Add RTL support where possible
▢ 린트
질문 3
다음 중 칩에 관한 설명으로 옳지 않은 것은 무엇인가요?
▢ 칩을 ChipGroup의 일부로 표시합니다.
▢ ChipGroup의 색상 상태 목록을 제공할 수 있습니다.
▢ 칩은 입력, 속성 또는 작업을 나타내는 간단한 요소입니다.
▢ 앱에서 칩을 사용하는 경우 항상 DarkTheme를 사용 설정해야 합니다.
질문 4
어떤 테마가 어두운 모드와 밝은 모드의 스타일을 지정해 주나요?
▢ DayNight
▢ DarkTheme
▢ DarkAndLightTheme
▢ Light
질문 5
라이브 영역이란 무엇인가요?
▢ 사용자에게 중요한 정보가 포함된 노드
▢ Material 가이드라인에 따라 모양이 변하는 화면 영역
▢ 스트리밍 동영상을 허용하는 뷰
▢ 애니메이션 드로어블









