Text
컴포저블의 텍스트 문자열과 같이 컴포저블이 전달하는 기본 정보 외에도 UI 요소에 관한 추가 정보를 갖는 것이 유용할 수 있습니다.
Compose에서 구성요소의 의미와 역할에 관한 정보를 시맨틱이라고 합니다. 이는 접근성, 자동 완성, 테스트와 같은 서비스에 컴포저블에 관한 추가 컨텍스트를 제공하는 방법입니다. 예를 들어 카메라 아이콘은 시각적으로는 단지 이미지일 수 있지만 시맨틱 의미는 '사진 찍기'일 수 있습니다.
적절한 시맨틱을 적절한 Compose API와 결합하면 접근성 서비스에 구성요소에 관한 최대한 많은 정보를 제공할 수 있으며, 접근성 서비스는 이를 사용자에게 표시하는 방법을 결정합니다.
Material 및 Compose UI 및 Foundation API에는 특정 역할과 기능을 따르는 내장 시맨틱이 제공되지만, 특정 요구사항에 따라 기존 API의 시맨틱을 수정하거나 맞춤 구성요소에 새 시맨틱을 설정할 수도 있습니다.
시맨틱 속성
시맨틱 속성은 상응하는 컴포저블의 의미를 전달합니다. 예를 들어 Text
컴포저블에는 시맨틱 속성 text
가 포함되어 있습니다. 이 컴포저블의 의미이기 때문입니다. Icon
에는 텍스트로 아이콘의 의미를 전달하는 contentDescription
속성 (개발자가 설정한 경우)이 포함되어 있습니다.
시맨틱 속성이 컴포저블의 의미를 전달하는 방법을 고려하세요. Switch
을 고려해 보세요. 사용자에게는 다음과 같이 표시됩니다.

Switch
의 '켜짐' 및 '꺼짐' 상태이 요소의 의미를 설명하려면 다음과 같이 말할 수 있습니다. '이것은 스위치입니다. 스위치는 전환 가능한 요소이고 현재 '켜짐' 상태입니다. 스위치를 클릭하여 상호작용할 수 있습니다.'
이것이 시맨틱 속성이 사용되는 정확한 용도입니다. 이 스위치 요소의 시맨틱 노드에는 Layout Inspector로 시각화된 다음 속성이 포함되어 있습니다.

Switch
컴포저블의 시맨틱 속성을 보여주는 Layout InspectorRole
는 요소 유형을 나타냅니다. StateDescription
은 '켜짐' 상태를 어떻게 참조해야 하는지 설명합니다. 기본적으로 단순히 'On'이라는 단어의 현지화된 버전이지만 컨텍스트에 따라 더 구체적으로 될 수 있습니다 (예: '사용 설정됨'). ToggleableState
는 스위치의 현재 상태입니다. OnClick
속성은 이 요소와 상호작용하는 데 사용되는 메서드를 참조합니다.
앱에서 각 컴포저블의 시맨틱 속성을 추적하면 다음과 같은 여러 강력한 가능성이 열립니다.
- 접근성 서비스는 속성을 사용하여 화면에 표시되는 UI를 나타내고 사용자가 UI와 상호작용할 수 있도록 합니다. 스위치 컴포저블의 경우 TalkBack에서 '스위치 켜짐, 전환하려면 두 번 탭하세요'라고 안내할 수 있습니다. 사용자는 화면을 두 번 탭하여 스위치를 꺼짐으로 전환할 수 있습니다.
-
테스트 프레임워크는 속성을 사용하여 노드를 찾아 상호작용하고 어설션을 만듭니다.
val mySwitch = SemanticsMatcher.expectValue( SemanticsProperties.Role, Role.Switch ) composeTestRule.onNode(mySwitch) .performClick() .assertIsOff()
Compose 기초 라이브러리에 기반하여 빌드된 컴포저블과 수정자는 이미 기본적으로 관련 속성을 설정합니다. 원하는 경우 이러한 속성을 수동으로 변경하여 특정 사용 사례의 접근성 지원을 개선하거나 컴포저블의 병합 또는 삭제 전략을 변경할 수 있습니다.
구성요소의 특정 콘텐츠 유형을 접근성 서비스에 알리려면 다양한 시맨틱을 적용할 수 있습니다. 이러한 추가 기능은 기본 시맨틱 정보를 지원하고 접근성 서비스가 구성요소가 표시되거나, 공지되거나, 상호작용하는 방식을 미세 조정하는 데 도움이 됩니다.
시맨틱 속성의 전체 목록은 SemanticsProperties
객체를 참고하세요. 가능한 접근성 작업의 전체 목록은 SemanticsActions
객체를 참고하세요.
제목
앱에는 긴 기사나 뉴스 페이지와 같이 텍스트가 많은 콘텐츠가 포함된 화면이 포함되는 경우가 많으며, 이러한 화면은 일반적으로 제목이 있는 여러 하위 섹션으로 나뉩니다.

접근성 기능이 필요한 사용자는 이러한 화면을 쉽게 탐색하지 못할 수 있습니다. 탐색 환경을 개선하기 위해 일부 접근성 서비스에서는 섹션 또는 제목 간에 직접 더 쉽게 탐색할 수 있도록 허용합니다. 이를 사용 설정하려면 시맨틱 속성을 정의하여 구성요소가 heading
임을 나타냅니다.
@Composable private fun Subsection(text: String) { Text( text = text, style = MaterialTheme.typography.headlineSmall, modifier = Modifier.semantics { heading() } ) }
알림 및 팝업
구성요소가 Snackbar
와 같은 알림 또는 팝업인 경우 접근성 서비스에 새로운 구조 또는 콘텐츠 업데이트를 사용자에게 전달할 수 있다고 신호를 보낼 수 있습니다.
알림과 유사한 구성요소는 liveRegion
시맨틱 속성으로 표시할 수 있습니다. 이렇게 하면 접근성 서비스가 이 구성요소 또는 그 하위 요소의 변경사항을 사용자에게 자동으로 알릴 수 있습니다.
PopupAlert( message = "You have a new message", modifier = Modifier.semantics { liveRegion = LiveRegionMode.Polite } )
사용자의 주의가 화면의 알림이나 중요한 변경 콘텐츠에 잠시만 집중되어야 하는 대부분의 경우 liveRegionMode.Polite
를 사용해야 합니다.
방해가 되는 의견을 피하려면 liveRegion.Assertive
를 가급적 사용하지 않는 것이 좋습니다.
시간에 민감한 콘텐츠를 사용자에게 알리는 것이 중요한 경우에 사용해야 합니다.
PopupAlert( message = "Emergency alert incoming", modifier = Modifier.semantics { liveRegion = LiveRegionMode.Assertive } )
실시간 영역은 카운트다운 타이머와 같이 자주 업데이트되는 콘텐츠에는 사용하면 안 됩니다. 끊임없는 피드백으로 사용자에게 부담을 주지 않기 위해서입니다.
창과 같은 구성요소
ModalBottomSheet
와 마찬가지로 창과 같은 맞춤 구성요소는 주변 콘텐츠와 구별하기 위해 추가 신호가 필요합니다. 이를 위해 paneTitle
시맨틱을 사용하면 관련 창 또는 창 변경사항이 기본 시맨틱 정보와 함께 접근성 서비스에 의해 적절하게 표현될 수 있습니다.
ShareSheet( message = "Choose how to share this photo", modifier = Modifier .fillMaxWidth() .align(Alignment.TopCenter) .semantics { paneTitle = "New bottom sheet" } )
참고로 Material 3에서 구성요소에 paneTitle
를 사용하는 방법을 확인하세요.
오류 구성요소
오류와 같은 구성요소와 같은 다른 콘텐츠 유형의 경우 접근성 요구사항이 있는 사용자를 위해 기본 시맨틱 정보를 확장하는 것이 좋습니다.
오류 상태를 정의할 때 접근성 서비스에 error
시맨틱을 알리고 확장된 오류 메시지를 제공할 수 있습니다.
이 예에서는 TalkBack이 기본 오류 텍스트 정보를 읽은 후 추가 확장 메시지를 읽습니다.
Error( errorText = "Fields cannot be empty", modifier = Modifier .semantics { error("Please add both email and password") } )
진행률 추적 구성요소
진행 상황을 추적하는 맞춤 구성요소의 경우 현재 진행 상황 값, 범위, 단계 크기를 비롯한 진행 상황 변경사항을 사용자에게 알리는 것이 좋습니다. progressBarRangeInfo
시맨틱을 사용하면 됩니다. 이렇게 하면 접근성 서비스가 진행 상황 변경사항을 인식하고 적절하게 사용자를 업데이트할 수 있습니다. 또한 다양한 보조 기술마다 진행 상황을 늘리거나 줄이는 데 사용하는 고유한 방법이 있을 수 있습니다.
ProgressInfoBar( modifier = Modifier .semantics { progressBarRangeInfo = ProgressBarRangeInfo( current = progress, range = 0F..1F ) } )
목록 및 항목 정보
항목이 많은 맞춤 목록과 그리드에서는 접근성 서비스가 총 항목 수 및 색인과 같은 더 자세한 정보를 수신하는 것이 유용할 수 있습니다.
이 긴 목록에서 접근성 서비스는 목록과 항목에 각각 collectionInfo
및 collectionItemInfo
시맨틱을 사용하여 텍스트 시맨틱 정보 외에도 전체 컬렉션에서 현재 어느 항목 색인에 있는지 사용자에게 알릴 수 있습니다.
MilkyWayList( modifier = Modifier .semantics { collectionInfo = CollectionInfo( rowCount = milkyWay.count(), columnCount = 1 ) } ) { milkyWay.forEachIndexed { index, text -> Text( text = text, modifier = Modifier.semantics { collectionItemInfo = CollectionItemInfo(index, 0, 0, 0) } ) } }
상태 설명
컴포저블은 Android 프레임워크에서 컴포저블의 상태를 읽는 데 사용하는 시맨틱의 stateDescription
을 정의할 수 있습니다. 예를 들어 전환 가능한 컴포저블의 상태는 '선택됨' 또는 '선택 해제됨'일 수 있습니다. 경우에 따라 Compose에서 사용하는 기본 상태 설명 라벨을 재정의할 수 있습니다. 이렇게 하려면 컴포저블을 전환 가능한 컴포저블로 정의하기 전에 상태 설명 라벨을 명시적으로 지정하면 됩니다.
@Composable private fun TopicItem(itemTitle: String, selected: Boolean, onToggle: () -> Unit) { val stateSubscribed = stringResource(R.string.subscribed) val stateNotSubscribed = stringResource(R.string.not_subscribed) Row( modifier = Modifier .semantics { // Set any explicit semantic properties stateDescription = if (selected) stateSubscribed else stateNotSubscribed } .toggleable( value = selected, onValueChange = { onToggle() } ) ) { /* ... */ } }
맞춤 작업
맞춤 작업은 스와이프하여 닫기 또는 드래그 앤 드롭과 같이 더 복잡한 터치 스크린 동작에 사용할 수 있습니다. 운동 장애 또는 기타 장애가 있는 사용자는 이러한 동작을 사용하기 어려울 수 있기 때문입니다.
스와이프하여 닫기 동작의 접근성을 높이려면 닫기 작업과 라벨을 전달하여 맞춤 작업에 연결하면 됩니다.
SwipeToDismissBox( modifier = Modifier.semantics { // Represents the swipe to dismiss for accessibility customActions = listOf( CustomAccessibilityAction( label = "Remove article from list", action = { removeArticle() true } ) ) }, state = rememberSwipeToDismissBoxState(), backgroundContent = {} ) { ArticleListItem() }
그러면 TalkBack과 같은 접근성 서비스가 구성요소를 강조 표시하고 메뉴에 더 많은 작업이 있음을 암시하며 왼쪽 스와이프하여 닫기 작업을 나타냅니다.

맞춤 작업의 또 다른 사용 사례는 사용할 수 있는 작업이 더 많은 항목이 포함된 긴 목록입니다. 사용자가 모든 항목에 대해 각 작업을 개별적으로 반복하는 것은 번거로울 수 있기 때문입니다.

스위치 액세스 또는 음성 액세스와 같은 상호작용 기반 보조 기술에 특히 유용한 탐색 환경을 개선하려면 컨테이너에서 맞춤 작업을 사용하여 작업을 개별 탐색에서 별도의 작업 메뉴로 이동할 수 있습니다.
ArticleListItemRow( modifier = Modifier .semantics { customActions = listOf( CustomAccessibilityAction( label = "Open article", action = { openArticle() true } ), CustomAccessibilityAction( label = "Add to bookmarks", action = { addToBookmarks() true } ), ) } ) { Article( modifier = Modifier.clearAndSetSemantics { }, onClick = openArticle, ) BookmarkButton( modifier = Modifier.clearAndSetSemantics { }, onClick = addToBookmarks, ) }
이 경우 맞춤 작업으로 이동하므로 clearAndSetSemantics
수정자를 사용하여 원래 하위 요소의 시맨틱을 수동으로 삭제해야 합니다.
스위치 제어를 예로 들면 컨테이너를 선택하면 메뉴가 열리고 사용 가능한 중첩 작업이 표시됩니다.


시맨틱 트리
컴포지션은 앱의 UI를 설명하고 컴포저블을 실행하여 생성됩니다. 컴포지션은 UI를 설명하는 컴포저블로 구성된 트리 구조입니다.
컴포지션 옆에는 시맨틱 트리라는 병렬 트리가 있습니다. 이 트리는 접근성 서비스와 테스트 프레임워크에서 이해할 수 있는 대체 방식으로 UI를 설명합니다. 접근성 서비스는 이 트리를 사용하여 특정 요구사항이 있는 사용자에게 앱을 설명합니다. 테스트 프레임워크는 이 트리를 사용하여 앱과 상호작용하고 이에 관한 어설션을 만듭니다. 시맨틱 트리에는 컴포저블을 그리는 방법은 포함되어 있지 않지만 컴포저블의 시맨틱 의미에 관한 정보는 포함되어 있습니다.

앱이 Compose 기초 및 Material 라이브러리의 컴포저블과 수정자로 구성되어 있다면 시맨틱 트리가 자동으로 채워지고 생성됩니다. 그러나 맞춤 하위 수준 컴포저블을 추가할 때는 시맨틱을 수동으로 제공해야 합니다. 트리가 화면에 있는 요소의 의미를 올바르게 또는 완전히 나타내지 못하는 경우도 있을 수 있으며 이 경우 트리를 조정할 수 있습니다.
예를 들어 다음 맞춤 캘린더 컴포저블을 생각해보세요.

이 예에서 전체 캘린더는 Layout
컴포저블을 사용하고 Canvas
에 직접 그리는 단일 하위 수준 컴포저블로 구현됩니다.
다른 작업을 하지 않으면 접근성 서비스에서는 컴포저블의 콘텐츠와 캘린더 내의 사용자 선택사항에 관한 정보를 충분히 수신하지 못합니다. 예를 들어 사용자가 17이 포함된 날짜를 클릭하면 접근성 프레임워크는 전체 캘린더 컨트롤에 관한 설명 정보만 수신합니다. 이 경우 TalkBack 접근성 서비스는 단순히 '캘린더' 또는 약간 더 나은 '4월 캘린더'만 알릴 뿐이고 사용자는 어떤 날짜가 선택되었는지 알 수 없습니다. 이 컴포저블에 더 쉽게 액세스할 수 있도록 하려면 시맨틱 정보를 수동으로 추가해야 합니다.
병합된 트리와 병합되지 않은 트리
앞서 언급했듯이 UI 트리의 각 컴포저블에는 시맨틱 속성이 0개 이상 설정되어 있을 수 있습니다. 컴포저블에 시맨틱 속성이 설정되어 있지 않으면 컴포저블은 시맨틱 트리의 일부로 포함되지 않습니다. 따라서 시맨틱 트리에는 실제로 시맨틱 의미가 포함된 노드만 포함됩니다. 그러나 때로는 화면에 표시되는 내용의 정확한 의미를 전달하기 위해 노드의 특정 하위 트리를 병합하여 하나로 처리하는 것도 유용합니다. 이렇게 하면 각 하위 노드를 개별적으로 처리하는 대신 전체로서 일련의 노드를 추론할 수 있습니다. 일반적으로 이 트리의 각 노드는 접근성 서비스를 사용할 때 포커스 가능 요소를 나타냅니다.
이러한 컴포저블의 예로는 Button
가 있습니다. 여러 하위 노드가 포함되어 있을 수 있지만 단일 요소로 버튼을 추론할 수 있습니다.
Button(onClick = { /*TODO*/ }) { Icon( imageVector = Icons.Filled.Favorite, contentDescription = null ) Spacer(Modifier.size(ButtonDefaults.IconSpacing)) Text("Like") }
시맨틱 트리에서 버튼의 하위 요소 속성이 병합되고 버튼은 트리에서 단일 리프 노드로 표시됩니다.

컴포저블과 수정자는 Modifier.semantics
(mergeDescendants = true) {}
를 호출하여 하위 요소의 시맨틱 속성을 병합하려고 함을 나타낼 수 있습니다. 이 속성을 true
로 설정하면 시맨틱 속성을 병합해야 함을 나타냅니다. Button
예에서 Button
컴포저블은 이 semantics
수정자가 포함된 clickable
수정자를 내부적으로 사용합니다. 따라서 버튼의 하위 노드가 병합됩니다.
컴포저블에서 병합 동작을 변경해야 하는 시기에 관한 자세한 내용은 접근성 문서를 참고하세요.
Foundation 및 Material Compose 라이브러리의 여러 수정자와 컴포저블에는 이 속성이 설정되어 있습니다. 예를 들어 clickable
과 toggleable
수정자는 자동으로 하위 요소를 병합합니다. ListItem
컴포저블도 하위 요소를 병합합니다.
트리 검사
시맨틱 트리는 실제로 두 개의 서로 다른 트리입니다. 하나는 병합된 시맨틱 트리로, 이 트리는 mergeDescendants
가 true
로 설정될 때 하위 노드를 병합합니다.
다른 하나는 병합되지 않은 시맨틱 트리로, 이 트리는 병합을 적용하지 않지만 모든 노드를 그대로 유지합니다. 접근성 서비스는 병합되지 않은 트리를 사용하고 mergeDescendants
속성을 고려하여 자체 병합 알고리즘을 적용합니다. 테스트 프레임워크는 기본적으로 병합된 트리를 사용합니다.
printToLog()
메서드로 두 트리를 모두 검사할 수 있습니다. 기본적으로 앞의 예와 마찬가지로 병합된 트리가 기록됩니다. 대신 병합되지 않은 트리를 인쇄하려면 다음과 같이 onRoot()
매처의 useUnmergedTree
매개변수를 true
로 설정합니다.
composeTestRule.onRoot(useUnmergedTree = true).printToLog("MY TAG")
Layout Inspector를 사용하면 뷰 필터에서 선호하는 트리를 선택하여 병합된 시맨틱 트리와 병합되지 않은 시맨틱 트리를 모두 표시할 수 있습니다.

트리의 각 노드의 경우 Layout Inspector에는 병합된 시맨틱과 속성 패널에서 이 노드에 설정된 시맨틱이 모두 표시됩니다.

기본적으로 테스트 프레임워크의 매처는 병합된 시맨틱 트리를 사용합니다.
따라서 Button
안에 표시된 텍스트를 일치시켜 Button
와 상호작용할 수 있습니다.
composeTestRule.onNodeWithText("Like").performClick()
onRoot
매처와 마찬가지로 매처의 useUnmergedTree
매개변수를 true
로 설정하여 이 동작을 재정의합니다.
트리 조정
앞서 언급했듯이 특정 시맨틱 속성을 재정의 또는 삭제하거나 트리의 병합 동작을 변경할 수 있습니다. 자체 맞춤 구성요소를 만들 때 특히 유용합니다. 올바른 속성과 병합 동작을 설정하지 않으면 앱에 액세스하지 못할 수 있으며 테스트가 예상과 다르게 동작할 수 있습니다. 테스트에 관한 자세한 내용은 테스트 가이드를 참고하세요.
추천 서비스
- 참고: JavaScript가 사용 중지되어 있으면 링크 텍스트가 표시됩니다.
- Compose의 접근성
- Compose의 Material Design 2
- Compose 레이아웃 테스트