旋转输入是指来自手表旋转或转动的部件的输入。平均而言,用户在与手表互动时只花几秒钟。您可以通过使用旋转输入来允许用户快速完成各种任务,从而增强用户体验。
大多数手表上的三个主要旋转输入来源包括旋转侧按钮 (RSB),以及物理边框或触摸边框,即屏幕周围的圆形触摸区域。虽然预期行为可能根据输入类型而有所不同,但请确保为所有基本交互支持旋转输入。
滚动
大多数用户希望应用支持滚动手势。当内容在屏幕上滚动时,在响应旋转交互时为用户提供视觉反馈。视觉反馈可以包括 位置指示器 用于垂直滚动,或 页面指示器。
使用 Compose for Wear OS 实现旋转滚动。此示例描述了一个具有脚手架和 ScalingLazyColumn
的应用,该应用垂直滚动。脚手架为 Wear OS 应用提供基本布局结构,并且已经有一个滚动指示器的插槽。要显示滚动进度,请根据列表状态对象创建位置指示器。可滚动视图(包括 ScalingLazyColumn
)已经具有可滚动状态以添加旋转输入。要接收旋转滚动事件,请执行以下操作
使用
FocusRequester
明确请求焦点。对于更复杂的情况,例如HorizontalPager
中的多个ScalingLazyColumns
对象,请使用HierarchicalFocusCoordinator
。添加
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(),
) { ... }
其他资源
请考虑使用 Horologist,这是一个 Google 开源项目,提供了一组 Wear 库,这些库补充了 Compose for Wear OS 和其他 Wear OS API 提供的功能。Horologist 为高级用例提供实现,以及许多设备特定的细节。
例如,不同旋转输入源的灵敏度可能会有所不同。为了使值之间的过渡更加平滑,您可以对速度进行限制或添加捕捉或动画过渡。这使得转动速度对用户来说更自然。Horologist 包括用于可滚动组件和离散值的修饰符。它还包括用于处理焦点的实用程序以及一个音频 UI 库,用于通过触觉反馈实现音量控制。
有关更多信息,请参阅 GitHub 上的 Horologist。
推荐给您
- 注意:当 JavaScript 关闭时,链接文本将显示。
- 更改焦点行为
- 使用 Jetpack Compose 添加键盘、鼠标、触控板和触控笔支持
- Compose for Wear OS 代码实验室