Android Accessibility: Semantics
Composition(컴포지션)은 앱의 UI(유아이)를 설명하고 composables(컴포져블)를 실행하여 UI를 만듭니다. Composition은 tree(트리) 구조이고, UI를 설명하는 요소로 구성되어 있습니다.
Composition 옆에는 비슷한 병렬구조의 Semantics(의미) tree가 있습니다. 이 tree는 UI를 Accessibility(접근성) 서비스와 테스트 framework(프레임워크)에 다른 방식으로 설명합니다. Accessibility 서비스는 tree를 이용하여 특별한 요구사항으로 사용자에게 설명합니다. 테스트 framework는 앱과 상호작용하며 assertions(어썰션)에 이용합니다. Semantics tree는 UI를 어떻게 그려야 하는지에 대한 정보를 포함하고 있지 않습니다. 대신 당신의 composables의 semantic meaning(의미)을 가집니다.
만약 당신의 앱이 composables로 구성되어 있고, Compose(컴포즈) 기초와 material library를 사용하여 변경을 시키게 된다면, Semantics tree는 자동으로 채워져서 생성될 것입니다. 그러나, 당신이 custom(사용자가 수정한) 한 low-level(낮은 수준)의 composables를 추가한다면, 당신은 수동으로 semantics를 추가해야 합니다. 이러한 상황에서는 당신의 tree는 올바르지 않거나, 화면의 전체 의미를 대변할 뿐입니다. 이경우 당신은 tree를 변경할 수 있습니다.
아래의 custom된 달력 예시를 보시죠.
이 예시에서 전체 달력은 low-level composable로 사용되었습니다. layout(레이아웃) composable을 사용하여 직접적으로 Canvas(캔버스)에 그렸습니다. 만약 당신이 아무것도 하지 않는다면, accessibility 달력 내용에 대한 충분한 정보를 전달받지 못합니다. 그리고 달력 안의 사용자 클릭도 전달받지 못합니다. 예를 들어, 만약 사용자가 17일을 선택하게 되면, accessibility framework는 전체 달력에 대한 정보만 얻게 됩니다. 이 경우 TalkBack(토크 백) accessibility 서비스는 달력이라고 말하거나 4월 달력이라고 말할 뿐이라 사용자는 어느 날을 선택한 건지 알 수가 없게 됩니다. 이러한 composable이 좀 더 접근성이 좋게 하려면, 당신은 수동으로 semantic 정보를 넣어줘야 합니다.
⊙ Semantics properties: 의미 속성;
UI tree에 있는 모든 nodes(노드)가 가진 semantic 의미는 Semantics tree에도 평행하게 존재합니다. Semantics tree에 있는 모든 node들은 composable에 알맞은 의미를 나타내는 properties(속성)을 가집니다. 예를 들어, Text(글자) composable은 text라는 semantic property를 가집니다. 왜냐하면 이것은 composable의 의미이기 때문입니다. Icon은 contentDescription(내용 설명) property를 가지며, 이것은 개발자가 설정한 값이 Icon의 의미를 설명하는 것이 됩니다. Comoposables와 modifiers(모디파이어)는 Compose의 기본 라이브러리로 만들어졌기 때문에 이미 관련된 properties가 설정되어 있습니다. 선택적으로 당신은 이렇나 properties를 override(오버라이드) 하여 semaintics를 새로 설정하거나 clearAndSetSemantics modifiers를 사용할 수도 있습니다. 예를 들어, 당신은 custom accessibility actions를 node에 추가할 수 있고 토글 요소에 다른 설명을 부여할 수 있습니다. 또는 특정한 text composable을 heading(시작 지점)으로 설정할 수 있습니다.
Semantics tree를 시각화하기 위해서는 Layout Inspector를 사용할 수 있습니다. 또는 printToLog()를 test에 사용할 수 있습니다. 이것은 Logcat에 Semantics tree를 보여줍니다.
출력은 다음과 같습니다.
Switch(스위치)를 예로 들어 어떻게 semantics properties가 composable의 의미를 전달하는지 봅시다.
이 요소를 설명하기 위해서 다음과 같이 설명할 수 있습니다. "This is a Switch, which is a toggleable element, currently in its 'On' state. You can click it to interact with it." (이것은 스위치입니다. 토글이 가능한 요소이며, 현재는 켜짐 상태입니다. 당신은 클릭하여 스위치와 상호작용할 수 있습니다.)
이것은 정확히 semantics properties가 하는 것과 동일합니다. 스위치의 Semantics node는 다음과 같은 properties를 가집니다. Layout Inspector를 보시죠.
Role은 요소의 종류를 나타냅니다. StateDescription은 켜짐 상태일 때를 설명합니다. 일반적으로 On은 현지화되어 나타나집니다. 때론 문맥에 따라서 Enabled(가능함)이 적절할 수 있습니다. ToggleableState는 스위치의 현재 상태를 나타냅니다. SemanticsProperties object(오브젝트)를 확인해 보세요. 전체 가능한 Accessibility Actions(액션)을 보려면 SemanticsActions object를 보세요.
계속해서 semantics properties를 추적하는 것은 당신의 앱의 가능성을 열어줍니다.
• Talkback이 큰 소리로 읽어줘서 사용자가 부드럽게 앱을 사용할 수 있습니다. 우리의 스위치의 경우 이렇게 말합니다. On; Switch; double tap to toggle; (켜짐; 스위치; 두 번 클릭하여 토글을 변경하세요;) 사용자는 두 번 클릭하여 스위치를 끌 수 있습니다.
• 테스트 framework가 properties를 사용하여 nodes를 찾고, 상호작용하며, assertions가 가능합니다. 간단한 예시입니다.
• 메모:
앱을 개발하는 동안 당신은 올바른 의미를 semantics properties에 전달하도록 노력해야 합니다. 여러 accessibility 서비스를 사용하여 좋은 결과가 나오는지 확인해야 합니다. 철저히 테스트하기 위해서 accessibility에 영향을 주는 semantics properties를 추가하는 것이 아니라면, 기본으로 제공해 주는 것을 사용합니다.
⊙ Merged and unmerged Semantics tree: 의미 합치기, 분할하기;
위에서 설명한 데로 UI tree에 있는 composable은 0 ~ 여러 개의 semantics properties 모둠을 가집니다. Composable이 semantics properties 모둠을 가지지 않을 때에는 Semantics tree에 포함되지 않습니다. 그러므로, Semantics tree는 semantic을 가지고 있는 요소만 포함합니다. 하지만, 가끔 화면의 요소들을 잘 설명하기 위해서 여러 개의 곁가지들을 합쳐 하나로 다루는 것이 유용할 때가 있습니다. 이것이 바로 개별 nodes를 하나로 뭉치는 이유입니다. 기본적으로 tree 안에 있는 모든 node는 accessibility 서비스가 접근할 수 있는 focusable(포커스 가능한) 요소입니다.
Button(버튼)을 예로 들어봅시다. 우리는 Button을 여러 개의 자식 nodes가 있더라도 하나로 다뤄봅시다.
Semantics tree에서 Button은 descendants(하위) merged가 되어 하나의 잎 node로 나타납니다.
Composables와 modifiers는 Modifier.semantics (mergeDescendants = true) {}로 하나로 합칠 수 있습니다. true로 설정하면 semantics properties는 합쳐집니다. 우리의 Button을 예로 들면, clickable modifier를 사용하고 이는 내부적으로 semantics modifier를 포함합니다. 그러므로 button의 descendant nodes는 자동으로 합쳐집니다. 당신의 composable의 merging behavior를 변경할 필요가 있다면 accessibility 문서를 읽어보세요.
Material Compose library와 Foundation에 있는 몇 가지 modifiers와 composables는 이러한 property 모둠을 가집니다. 예를 들어, clickable과 toggleable modifiers는 자동으로 하위 요소를 합칩니다. 또한, ListItem composable은 자동으로 합칩니다.
- Inspecting the trees: 나무 살펴보기;
우리가 Semantics tree를 언급할 때, 사실 다른 두 trees를 다룹니다. mergeDescendants가 true로 설정된 하위 요소가 합쳐진 merged Semantics tree와 merge가 적용되지 않은 모든 node가 그대로 유지된 unmerged Semantics tree입니다. Accessibility 서비스는 unmerged tree를 사용하고, 자신만의 합치기 알고리듬을 적용하여 mergeDescendants property에 넣습니다. 테스트 framework는 merged tree를 기본으로 사용합니다.
당신은 두 tree를 printToLog()를 사용하여 볼 수 있습니다. 위의 예제와 같이 기본적으로 merged tree가 보입니다. unmerged tree를 출력하고 싶다면, useUnmergedTree parameter를 onRoot에 true로 넣습니다.
Layout Inspector 또한 merged와 unmerged Semantics tree를 보여줍니다. view filter에서 선택할 수 있습니다.
Tree 안에 있는 각각의 node는 Layout Inspector의 properties 패널에 Merged Semantics와 Semantics 모둠이 보입니다.
기본적으로 테스트 Framework의 matchers(일치 확인) 기능은 merged Semantics tree를 사용합니다. 이것이 Button을 text를 사용하여 찾을 수 있는 이유입니다.
당신은 이러한 행동을 matchers의 useUnmergedTree parameter를 true로 설정하여 override 할 수 있습니다. onRoot matcher에서 한 것과 동일합니다.
- Merging behavior: 합치기 행위;
하위 composable이 합쳐질 필요가 있을 때는 내부적으로 무슨 일이 일어날까요?
각각의 semantics property는 합치기 전략이 있습니다. 예를 들어 ContentDescription property는 모든 하위 요소의 ContentDescription 값을 목록으로 저장합니다. 당신은 SemanticsProperties.kt에 있는 mergePlicy를 확인하여 semantics property의 합치기 전략을 확인할 수 있습니다. Properties는 상위 또는 하위 값만 고르거나, 목록으로 저장하거나 글자로 저장하거나 골라야 합니다. 둘 다 사용하게 되면 오류가 발생합니다. 또는 custom 합치기 전략을 사용할 수 있습니다.
중요한 점은 하위 요소가 가진 mergeDescendants = true가 설정된 요소는 merge에 포함되지 않습니다. 예시를 보시죠.
여기에 우리는 클릭 가능한 목록 item(요소)가 있습니다. 사용자가 열을 누르게 되면, 앱은 사용자가 읽을 수 있게 기사 상세 보기 화면으로 넘어갑니다. 목록 item의 내부는 책갈피 버튼이 있습니다. 이 경우 우리는 복잡하게 얽힌 클릭 가능한 요소를 가지고 button은 merged tree에 분리되어 보입니다. 나머지 요소들은 합쳐져서 보입니다.
⊙ Adapting the Semantics tree: 의미 tree 적용하기;
위에서 언급한 것과 같이, 당신은 semantics properties를 지우거나, 합치기 행위를 변경할 수 있습니다. 이것은 특별히 당신만의 custom 요소를 만들 때 관련 있습니다. 적절한 properties와 합치기 행위를 설정하지 않으면, 당신의 앱은 접근성이 떨어지고, 테스트 결과가 당신의 예상과 다를 것입니다. Semantics tree를 사용하는 일반적인 사례를 보려면 accessibility 문서를 보세요. 테스트에 대해 알고 싶다면, Testing Guide를 확인하세요.
끝.
댓글
댓글 쓰기
궁금한 점은 댓글 달아주세요.
Comment if you have any questions.