로터리 입력은 시계에서 회전하는 부분의 입력을 의미합니다. 평균적으로 사용자가 시계와 상호작용하는 데는 몇 초밖에 걸리지 않습니다. 로터리 입력을 사용하면 사용자가 다양한 작업을 빠르게 완료할 수 있어 사용자 환경을 개선할 수 있습니다.
대부분의 시계에서 로터리 입력의 세 가지 기본 소스에는 회전 측면 버튼(RSB)과 물리적 베젤 또는 터치 베젤(화면 주변의 원형 터치 영역)이 있습니다. 예상되는 동작은 입력 유형에 따라 다를 수 있지만 모든 필수 상호작용에는 로터리 입력을 지원해야 합니다.
스크롤
대부분의 사용자는 앱이 스크롤 동작을 지원할 것으로 기대합니다. 콘텐츠가 화면에서 스크롤될 때 로터리 상호작용에 대한 응답으로 시각적 피드백을 사용자에게 제공합니다. 시각적 피드백에는 세로 스크롤을 위한 위치 표시기 또는 페이지 표시기가 포함될 수 있습니다.
Wear OS용 Compose를 사용하여 로터리 스크롤을 구현합니다. 이 예에서는 Scaffold가 있고 세로로 스크롤되는 ScalingLazyColumn
이 있는 앱을 설명합니다. Scaffold는 Wear OS 앱의 기본 레이아웃 구조를 제공하며 이미 스크롤 표시기를 위한 슬롯이 있습니다. 스크롤 진행률을 표시하려면 목록 상태 객체를 기반으로 위치 표시기를 만듭니다. ScalingLazyColumn
을 비롯한 스크롤 가능한 뷰에는 이미 로터리 입력을 추가하기 위한 스크롤 가능한 상태가 있습니다. 로터리 스크롤 이벤트를 수신하려면 다음을 실행하세요.
FocusRequester
를 사용하여 명시적으로 포커스를 요청합니다. 사용HierarchicalFocusCoordinator
- 복잡한 경우(예:HorizontalPager
의ScalingLazyColumns
객체onRotaryScrollEvent
수정자를 추가하여 사용자가 용두를 돌리거나 베젤을 회전할 때 시스템에서 생성되는 이벤트를 가로챕니다. 각 로터리 이벤트는 설정된 픽셀 값을 가지며 세로 또는 가로로 스크롤됩니다. 또한 수정자는 이벤트가 소비되는지를 나타내는 콜백이 있으며 소비될 때 상위 요소에 대한 이벤트 전파를 중지합니다.
val listState = rememberScalingLazyListState() Scaffold( positionIndicator = { PositionIndicator(scalingLazyListState = listState) } ) { val focusRequester = rememberActiveFocusRequester() val coroutineScope = rememberCoroutineScope() ScalingLazyColumn( modifier = Modifier .onRotaryScrollEvent { coroutineScope.launch { listState.scrollBy(it.verticalScrollPixels) listState.animateScrollBy(0f) } true } .focusRequester(focusRequester) .focusable() .fillMaxSize(), state = listState ) { // Content goes here // ... } }
불연속 값
로터리 상호작용을 사용하여 이산값을 조정할 수도 있습니다. 예를 들어 설정에서 밝기를 조정하거나 알람을 설정할 때 시간 선택 도구에서 숫자를 선택할 수 있습니다.
ScalingLazyColumn
과 마찬가지로 로터리 입력을 수신하려면 선택 도구, 슬라이더, 스테퍼 및 기타 컴포저블에 포커스가 있어야 합니다. 시간 선택 도구의 시간 및 분과 같이 화면에 스크롤 가능한 타겟이 여러 개 있는 경우 각 타겟에 FocusRequester
를 만들고 사용자가 시간이나 분을 탭할 때 적절히 포커스 변경을 처리합니다.
var selectedColumn by remember { mutableIntStateOf(0) } val hoursFocusRequester = remember { FocusRequester() } val minutesRequester = remember { FocusRequester() } // ... Scaffold(modifier = Modifier.fillMaxSize()) { Row( // ... // ... ) { // ... Picker( readOnly = selectedColumn != 0, modifier = Modifier.size(64.dp, 100.dp) .onRotaryScrollEvent { coroutineScope.launch { hourState.scrollBy(it.verticalScrollPixels) } true } .focusRequester(hoursFocusRequester) .focusable(), onSelected = { selectedColumn = 0 }, // ... // ... ) // ... Picker( readOnly = selectedColumn != 1, modifier = Modifier.size(64.dp, 100.dp) .onRotaryScrollEvent { coroutineScope.launch { minuteState.scrollBy(it.verticalScrollPixels) } true } .focusRequester(minutesRequester) .focusable(), onSelected = { selectedColumn = 1 }, // ... // ... ) LaunchedEffect(selectedColumn) { listOf( hoursFocusRequester, minutesRequester )[selectedColumn] .requestFocus() } } }
맞춤 작업
앱의 로터리 입력에 응답하는 맞춤 작업을 만들 수도 있습니다. 예를 들어 로터리 입력을 사용하여 확대/축소하거나 미디어 앱의 볼륨을 조절합니다.
구성요소가 볼륨 조절과 같은 스크롤 이벤트를 기본적으로 지원하지 않는 경우 직접 스크롤 이벤트를 처리할 수 있습니다.
// VolumeScreen.kt
val focusRequester: FocusRequester = remember { FocusRequester() }
Column(
modifier = Modifier
.fillMaxSize()
.onRotaryScrollEvent {
// handle rotary scroll events
true
}
.focusRequester(focusRequester)
.focusable(),
) { ... }
뷰 모델에서 관리되는 맞춤 상태와 로터리 스크롤 이벤트를 처리하는 데 사용되는 맞춤 콜백을 만듭니다.
// VolumeViewModel.kt
object VolumeRange(
public val max: Int = 10
public val min: Int = 0
)
val volumeState: MutableStateFlow<Int> = ...
fun onVolumeChangeByScroll(pixels: Float) {
volumeState.value = when {
pixels > 0 -> min (volumeState.value + 1, VolumeRange.max)
pixels < 0 -> max (volumeState.value - 1, VolumeRange.min)
}
}
편의상 위의 예에서는 픽셀 값을 사용하는데, 실제로 사용하는 경우에는 과도하게 민감할 수 있습니다.
이벤트를 받으면 다음 스니펫과 같이 콜백을 사용합니다.
val focusRequester: FocusRequester = remember { FocusRequester() }
val volumeState by volumeViewModel.volumeState.collectAsState()
Column(
modifier = Modifier
.fillMaxSize()
.onRotaryScrollEvent {
volumeViewModel
.onVolumeChangeByScroll(it.verticalScrollPixels)
true
}
.focusRequester(focusRequester)
.focusable(),
) { ... }
추가 리소스
Google 오픈소스 프로젝트인 Horologist를 사용해 보세요. Wear OS용 Compose 및 기타 Wear OS API에서 제공하는 기능을 보완하는 Wear 라이브러리 세트를 제공합니다. Horologist는 고급 사용 사례 구현과 여러 기기별 세부정보를 제공합니다.
예를 들어 다양한 로터리 입력 소스의 민감도는 다를 수 있습니다. 값 간의 전환을 더 원활하게 하려면 비율 제한을 적용하거나 전환을 위한 맞추기 또는 애니메이션을 추가할 수 있습니다. 이렇게 하면 사용자에게 회전 속도가 더 자연스럽게 느껴질 수 있습니다. Horologist에는 스크롤 가능한 구성요소 및 이산값의 수정자가 포함되어 있습니다. 포커스를 처리하는 유틸리티와 햅틱으로 볼륨 조절을 구현하는 오디오 UI 라이브러리도 포함되어 있습니다.
자세한 내용은 GitHub의 Horologist를 참고하세요.
추천 서비스
- 참고: JavaScript가 사용 중지되어 있으면 링크 텍스트가 표시됩니다.
- 포커스 동작 변경
- Jetpack Compose로 키보드, 마우스, 트랙패드, 스타일러스 지원 추가
- Wear OS용 Compose Codelab