Wear OS 7 (API 수준 37)부터 Wear OS용 Compose의 일부인 API와 함께 한 손 동작 프레임워크를 사용하면 사용자가 터치 없이 앱과 상호작용할 수 있습니다.
이 프레임워크는 처음에는 Pixel Watch 기기 (Pixel Watch 3 이상)에서 지원되었지만 이제 모든 OEM에서 사용할 수 있습니다. 이 API를 채택하면 하드웨어 지원이 확장됨에 따라 앱의 동작 지원이 생태계 전반에서 자동으로 확장됩니다.
사용자가 UI를 어수선하게 만들지 않고 사용 가능한 동작을 찾을 수 있도록 Wear OS 프레임워크는 애니메이션 동작 표시기를 제공합니다. 이러한 시각적 힌트는 동작을 실행할 수 있는 위치를 강조 표시하며, 시스템은 사용자 환경설정에 따라 표시 케이던스와 음소거 빈도를 자동으로 관리합니다.
지원되는 동작 및 작업
Wear OS 동작 프레임워크는 두 가지 동작 유형을 지원합니다.
- 기본 작업 (두 번 핀치): 통화 수신 또는 미디어 재생 전환과 같은 화면의 기본 작업에 매핑됩니다.
- 닫기 작업 (손목 돌리기): 뒤로 탐색, 대화상자 닫기 또는 프롬프트 취소에 매핑됩니다.
Compose에서 동작 구성
한 손 동작 API는 UI를 개선할 수 있지만 일부 하드웨어 및 OEM은 이러한 동작을 지원하지 않는다는 점을 염두에 두어야 합니다. API에서 앱이 지원되지 않는 기기 중 하나에서 실행 중임을 감지하면 라이브러리는 표준 터치 상호작용에 영향을 주지 않고 자동으로 no-op됩니다.
표준 Compose 동작과 마찬가지로 수정자를 사용하여 UI
요소에서 한 손 동작을 사용 설정합니다. 수행할 작업(기본 또는 닫기)과 힌트 표시 케이던스 및 음소거 빈도와 같은 시스템 수준 사용자 환경설정과 조정할 gestureId에 따라 앱의 동작을 구성합니다. 이 구성을 표현하려면
OneHandedGestureConfiguration 객체를 만드세요. 이 객체를 만들 때
rememberOneHandedGestureConfiguration 함수를 사용하는 것이 좋습니다. OneHandedGestureConfiguration에서 동작 우선순위를 제공할 수도 있습니다.
rememberOneHandedGestureConfiguration 함수는 애플리케이션 상태를 노출하지 않고 재구성 전반에서 사용자 상호작용 기록을 추적합니다. 앱에서 구성을 만든 후에는 구성 가능한 상호작용에서 구성을 Modifier.oneHandedGesture에 전달해야 합니다.
사용자가 사용 가능한 동작을 찾을 수 있도록 라이브러리는 OneHandedGestureClickIndicator 메서드를 제공합니다. 이 메서드는 기본 콘텐츠를 대체하여 사용자에게 동작 작업을 사용할 수 있음을 나타내는 래퍼 역할을 합니다.
상호작용 구성요소
버튼과 같은 상호작용 컨트롤에서 동작을 사용 설정하려면 OneHandedGestureAction.Primary를 지정하는 구성을 만들고 oneHandedGesture 수정자를 적용합니다. 동일한 MutableInteractionSource를 컨트롤과 수정자 모두에 전달하여 동작 이벤트가 컨트롤에 시각적 누르기 의견을 내보내도록 합니다.
동작 표시기를 사용 설정하려면 OneHandedGestureClickIndicatorState의 인스턴스를 만들고 기억합니다. 그런 다음 시각적 의견을 트리거하려면 oneHandedGesture 수정자가 제공하는 onGestureAvailable 콜백 내에서 showIndicator를 호출합니다. 이는 시스템에 표시 이벤트가 발생했음을 알립니다. 호출되면 구성요소가 일반 콘텐츠를 동작 애니메이션으로 잠시 대체합니다.
var isPlaying by remember { mutableStateOf(false) } val onClick = { isPlaying = !isPlaying } val gestureConfig = rememberOneHandedGestureConfiguration( action = OneHandedGestureAction.Primary ) val indicatorState = remember { OneHandedGestureClickIndicatorState() } val coroutineScope = rememberCoroutineScope() val interactionSource = remember { MutableInteractionSource() } Button( onClick = onClick, interactionSource = interactionSource, modifier = Modifier .fillMaxWidth() .oneHandedGesture( gestureConfiguration = gestureConfig, interactionSource = interactionSource, onGestureLabel = if (isPlaying) "pause" else "play", onGestureAvailable = { coroutineScope.launch { indicatorState.showIndicator() } }, onGesture = onClick ) ) { OneHandedGestureClickIndicator( gestureConfiguration = gestureConfig, state = indicatorState ) { Text(if (isPlaying) "Pause" else "Play", modifier = Modifier.fillMaxWidth()) } }
스크롤 가능한 컨테이너
스크롤 가능한 화면 또는 목록의 경우 OneHandedGestureAction.Primary를 지정하는 구성을 만들고 컨테이너에 oneHandedGesture 수정자를 적용하여 scrollDown과 같은 스크롤 도우미를 호출합니다.
스크롤 작업에 시각적 의견을 제공하려면
OneHandedGestureScrollIndicator를 사용하면 됩니다. 이 구성요소는 스크롤 위치를 표시하는 표준 스크롤 표시기 역할을 하지만 사용자에게 스크롤 동작을 사용할 수 있음을 나타낼 수도 있습니다. 이 표시기는
일반적으로 scrollIndicator 슬롯에 전달되며
ScreenScaffold과 같은
스크롤 가능한 컨테이너의 상태와 결합됩니다.TransformingLazyColumn 또한 OneHandedGestureScrollIndicatorState를 관찰하여 시각적 전환을 관리합니다.
시각적 의견을 트리거하려면 이 상태에서 showIndicator를 호출합니다. 일반적으로 oneHandedGesture 수정자의 onGestureAvailable 콜백 내에서 호출합니다.
트리거되면 표시기가 표준 시각적 상태를 동작 애니메이션 시퀀스로 일시적으로 대체하여 사용자에게 알립니다.
val scrollState = rememberTransformingLazyColumnState() val gestureConfig = rememberOneHandedGestureConfiguration( action = OneHandedGestureAction.Primary, priority = OneHandedGesturePriority.Scrollable ) val indicatorState = remember(gestureConfig) { OneHandedGestureScrollIndicatorState() } val coroutineScope = rememberCoroutineScope() ScreenScaffold( scrollState = scrollState, scrollIndicator = { OneHandedGestureScrollIndicator( gestureConfiguration = gestureConfig, indicatorState = indicatorState, scrollState = scrollState, modifier = Modifier.align(Alignment.CenterEnd) ) } ) { contentPadding -> TransformingLazyColumn( state = scrollState, contentPadding = contentPadding, modifier = Modifier .fillMaxSize() .oneHandedGesture( gestureConfiguration = gestureConfig, onGestureLabel = "scroll", onGestureAvailable = { coroutineScope.launch { indicatorState.showIndicator() } }, onGesture = { OneHandedGestureDefaults.scrollDown(scrollState) } ) ) { items(10) { index -> Text("Item $index", modifier = Modifier.padding(8.dp)) } } }
여러 동작 결합
OneHandedGestureConfiguration 객체에 gesturePriority를 추가하여 동일한 기본 작업으로 스크롤 동작과 클릭 동작을 모두 구성할 수 있습니다.
OneHandedGesturePriority.Clickable(가장 높음): 화면에 표시될 때 동작을 캡처하도록Button또는Card유형이 있는 것과 같은 상호작용 컨트롤에 할당합니다.OneHandedGesturePriority.Scrollable(중간): 클릭 가능한 하위 요소에 양보하지만 클릭 가능한 컨트롤이 표시되지 않으면 스크롤하도록 스크롤 가능 또는 페이지 지정 가능한 컨테이너에 할당합니다.OneHandedGesturePriority.Unspecified(가장 낮음): 할당되지 않은 우선순위입니다.priority가 설정되지 않은 동작의 기본값입니다.
내부 버튼에 priority = OneHandedGesturePriority.Clickable을 명시적으로 설정하고 상위 목록에 priority = OneHandedGesturePriority.Scrollable을 설정하면 시스템에서 이 동작 우선순위 동작을 표시할 수 있습니다.
사용자가 한 손 동작으로 기본 작업을 트리거하면 먼저 버튼이 표시될 때까지 목록을 아래로 스크롤합니다. 그런 다음 버튼의 클릭 작업을 캡처합니다.
ADB로 동작 테스트 및 디버깅
Android 디버그 브리지 (adb) 및 IWearGestureService 시스템 서비스를 사용하여 실제 손목 움직임을 실행하지 않고 실제 기기 또는 에뮬레이터에서 한 손 동작을 테스트할 수 있습니다.
동작 시뮬레이션 사용 설정
- Wear OS 기기에서 Wear OS 7 (API 수준 37) 이상을 실행 중인지 확인합니다.
- 손목에 착용하지 않거나 충전기에 연결되지 않은 실제 기기에서 테스트하는 경우 기기가 활성 상태를 유지하도록 오프바디 센서 상태를 재정의합니다.
adb shell cmd sensorservice set-off-body-state 0
ADB를 사용하여 동작 이벤트 트리거
두 번 핀치 동작 (Pixel Watch의 Primary 작업)을 시뮬레이션하려면 다음 ADB 셸 명령어를 실행합니다.
adb shell cmd IWearGestureService gesture 1
손목 돌리기 동작 (Pixel Watch의 Dismiss 작업)을 시뮬레이션하려면 다음 ADB 셸 명령어를 실행합니다.
adb shell cmd IWearGestureService gesture 2
동작 힌트 추적 재설정
시스템은 사용자 상호작용 기록을 추적하고 전역 케이던스 설정 (예: 항상 또는 매일)에 따라 부동 동작 힌트를 표시합니다. 앱의 동작 표시기를 디버깅할 때 이 추적 기록을 재설정하여 패키지에 힌트가 다시 표시되도록 합니다.
adb shell cmd IWearGestureService hint clear <your_package_name>
테스트가 끝나면 오프바디 센서 상태를 재설정합니다.
adb shell cmd sensorservice reset-off-body-state
추가 리소스
한 손 동작을 사용할 시점과 위치에 관한 디자인 안내는 한 손 동작을 참고하세요.
추천 서비스
- 참고: JavaScript가 사용 중지되어 있으면 링크 텍스트가 표시됩니다.
- 한 손 동작 디자인 가이드