이 글은 Jetpack Compose 공식문서 - 시맨틱을 읽어보면서 정리한 글 입니다.
시맨틱이란 - 코드가 화면에서 어떻게 보여질까가 아닌 이 코드의 의미, 즉 역할은 무엇이며 기능은 무엇인가를 나타내는 것입니다.
참고 - Semantics
컴포지션은 앱의 UI를 설명하고 컴포저블을 실행하여 생성됩니다. 컴포지션은 UI를 설명하는 컴포저블로 구성된 트리 구조입니다.
컴포지션 옆에는 시맨틱 트리라는 병렬 트리가 있습니다. 이 트리는 접근성 서비스와 테스트 프레임워크에서 이해할 수 있는 방식으로 UI를 설명합니다.
테스트 프레임워크에서는 시맨틱 트리를 통해 앱과 상호작용 하고 어설션(assrtion)을 만듭니다.
시맨틱 트리에 컴포저블을 그리는 방법은 포함되어 있지 않지만 컴포저블의 시맨틱 의미에 관한 정보는 포함되어 있습니다.
앱이 Compose 기초 및 머티리얼 Composable과 수정자로 구성되어 있다면 시맨틱 트리가 자동으로 채워지고 생성됩니다. 하지만 맞춤설정을 한 Composable을 추가했다면 시맨틱을 수동으로 제공해야합니다.
이번 글에서는 Compose에서는 시맨틱을 어떻게 사용하고 관리하는지에 대해 알아보도록 하겠습니다😌.
시맨틱 트리의 노드에는 상응하는 Composable의 의미를 전달하는 속성이 포함되어 있습니다. 예를들어 Text
Composable에는 시맨틱 속성text
가 포함되어 있습니다.Icon
에는 Icon
의 의미를 전달하는 contentDescription
시맨틱 속성이 있습니다.
이처럼 Compose 기초라이브러리에 기반하여 빌드된 Composable과 수정자에는 이미 시맨틱 속성이 설정되어 있습니다. 그리고 필요에 따라 Modifier의 semantics
혹은 clearAndSetSemantics
을 사용하여 속성을 직접 설정하거나 재정의할 수 있습니다.
시맨틱 속성을 확인하려면 Layout Inspector 도구를 사용하거나 printToLong()
메서드를 사용하면 됩니다. 그러면 Logcat에 현재 시맨틱 트리가 출력됩니다.
class MyComposeTest {
@get:Rule
val composeTestRule = createComposeRule()
@Test
fun MyTest() {
// Start the app
composeTestRule.setContent {
MyTheme {
Text("Hello world!")
}
}
// Log the full semantics tree
composeTestRule.onRoot().printToLog("MY TAG")
}
}
Printing with useUnmergedTree = 'false'
Node #1 at (l=0.0, t=63.0, r=221.0, b=120.0)px
|-Node #2 at (l=0.0, t=63.0, r=221.0, b=120.0)px
Text = '[Hello world!]'
Actions = [GetTextLayoutResult]
스위치를 예시로 시맨틱 속성이 사용되는 용도를 설명하겠습니다.
위의 요소는 이렇게 설명할 수 있습니다. '이것은 스위치입니다. 스위치는 전환 가능한 요소이고 현재 '켜짐' 상태입니다. 스위치를 클릭하여 상호작용할 수 있습니다.'
이렇게 요소에 대해 설명하는것이 시맨틱 속성의 용도입니다.
앱에서 시맨틱 속성을 추적하면 여러 강력한 가능성이 열립니다.
val mySwitch = SemanticsMatcher.expectValue(
SemanticsProperties.Role, Role.Switch
)
composeTestRule.onNode(mySwitch)
.performClick()
.assertIsOff()
UI 트리의 Composable에는 시맨틱 속성이 설정되어있지 않을 수 있습니다. Composable에 시맨틱 속성이 설정되어 있지 않으면 Composable은 시맨틱 트리에 포함되지 않습니다. 따라서 시맨틱 트리에는 실제로 시맨틱 의미가 포함된 노드만 포함됩니다.
그러나 때로는 화면에 표시되는 내용을 정확하게 전달하기 위해 노드의 특정 하위 트리를 병합하여 처리하는 것도 유용합니다. 이렇게 하면 하위 노드를 개별적으로 처리하는 대신 전체의 내용을 통해 일련의 노드를 추론할 수 있습니다. Modifier에서 semantics (mergeDescendants = true) {}
를 호출함으로 써 시멘틱 속성을 병합 하려고 함을 나타낼 수 있습니다. (mergeDescendants = true)
는 시멘틱 속성을 병합해야 함을 나타냅니다. clickable
,toggleable
,ListItem 컴포저블
은 하위 요소를 자동으로 병합합니다.
시맨틱 트리는 병합된 트리와 병합되지 않은 트리로 구분됩니다.
Layout Inspector를 사용하면 뷰 필터에서 선호하는 트리를 선택하여 병합된 시맨틱 트리와 병합되지 않은 시맨틱 트리를 모두 표시할 수 있습니다.
Layout Inspector에는 병합된 시맨틱과 속성 패널에서 이 노드에 설정된 시맨틱이 모두 표시됩니다.
각 시맨틱 속성에는 정의된 병합 전략이 있습니다. 예를 들어 ContentDescription 속성은 모든 하위 ContentDescription 값을 목록에 추가합니다. 속성은 항상 상위 값이나 하위 값을 선택합니다. 혹은 값을 목록이나 문자열에 병합하거나 병합을 아예 허용하지 않고 대신 예외를 발생시키거나 다른 맞춤 병합 전략을 선택할 수 있습니다.
자체적으로 mergeDescendants = true
로 설정한 하위요소는 병합에 포함되지 않습니다.
예를 들어 안에 토글버튼이 위치하고 있는 버튼이 있다고 가정해봅시다.
행을 누르면 상세화면으로 이동하고, 토글버튼을 누르면 북마크로 등록합니다.
이 경우 중첩된 클릭기능이 있으므로 행의 컨텐츠는 병합되지만, 토글버튼은 병합된 트리에서 별도로 표시됩니다.
시맨틱 속성은 재정의 또는 삭제하거나 트리의 병합 동작을 변경할 수 있습니다. 이는 자체 맞춤 구성요소를 만들 때 특히 유용합니다.
올바른 속성과 병합 동작을 설정하지 않으면 앱에 액세스하지 못할 수 있으며 테스트가 예상과 다르게 동작할 수 있습니다.
시맨틱 트리를 조정해야 하는 일반적인 사용 사례에 관한 자세한 내용은 접근성 문서를 참고하세요. 테스트에 관한 자세한 내용은 테스트 가이드를 참고하세요.
이렇게 해서 Compose의 시맨틱에 대해 알아보았습니다. 다음 글에서는 CompositionLocal에 대해 알아보도록 하겠습니다. 끝까지 읽어주셔서 감사합니다. 즐거운 개발되세요🤗.
참고
Compose의 시맨틱