Compose 中的旋转输入

旋转输入是指来自手表上旋转部件的输入。用户平均仅花费几秒钟与手表交互。您可以通过使用旋转输入来增强用户体验,以允许用户快速完成各种任务。

大多数手表上的三个主要旋转输入来源包括旋转侧按钮 (RSB),以及物理表圈或触摸表圈(屏幕周围的圆形触摸区域)。尽管预期行为可能会因输入类型而异,但请确保支持所有基本交互的旋转输入。

滚动

大多数用户期望应用支持滚动手势。当内容在屏幕上滚动时,请根据旋转交互向用户提供视觉反馈。视觉反馈可以包括用于垂直滚动的位置指示器或用于分页指示器

默认情况下,ScalingLazyColumnPicker 支持滚动手势,只要您需要将这些组件放置在 Scaffold 中即可。Scaffold 提供了 Wear OS 应用的基本布局结构,并且已经有一个用于滚动指示器的插槽。要显示滚动进度,请根据列表状态对象创建位置指示器,如下面的代码片段所示。

val listState = rememberScalingLazyListState()
Scaffold(
    positionIndicator = {
        PositionIndicator(scalingLazyListState = listState)
    }
) {
    // ...
}

您可以使用 ScalingLazyColumnDefaults.snapFlingBehaviorScalingLazyColumn 配置捕捉行为,如下面的代码片段所示。

val listState = rememberScalingLazyListState()
Scaffold(
    positionIndicator = {
        PositionIndicator(scalingLazyListState = listState)
    }
) {

    val state = rememberScalingLazyListState()
    ScalingLazyColumn(
        modifier = Modifier.fillMaxWidth(),
        state = state,
        flingBehavior = ScalingLazyColumnDefaults.snapFlingBehavior(state = state)
    ) {
        // Content goes here
        // ...
    }
}

自定义操作

您还可以创建自定义操作以响应应用中的旋转输入。例如,使用旋转输入放大和缩小或在媒体应用中控制音量。

如果您的组件本身不支持滚动事件(如音量控制),您可以自己处理滚动事件。

// 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(),
) { ... }