Rotary input with Compose

Rotary input refers to input from pieces of your watch that spin or rotate. On average, users spend only a few seconds interacting with their watch. You can enhance your user experience by using Rotary input to allow your user to quickly accomplish various tasks.

The three main sources of rotary input on most watches include the rotating side button (RSB), and either a physical bezel or a touch bezel, which is a circular touch zone around the screen. Though expected behavior may vary based on the type of input, be sure to support rotary input for all essential interactions.

Scroll

Most users expect apps to support the scroll gesture. As the content scrolls on the screen, give the users visual feedback in response to rotary interactions. Visual feedback can include position indicators for vertical scroll or page indicators.

ScalingLazyColumn and Picker support the scroll gesture by default, as long as you need to place those components inside a Scaffold. Scaffold provides the basic layout structure for Wear OS apps and already has a slot for a scroll indicator. To show the scrolling progress, create a position indicator based on the list state object, as shown in the following code snippet:

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

You can configure a snap behavior for ScalingLazyColumn by using ScalingLazyColumnDefaults.snapFlingBehavior, as shown in the following code snippet:

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
        // ...
    }
}

Custom actions

You can also create custom actions that respond to rotary input in your app. For example, use rotary input to zoom in and out or to control volume in a media app.

If your component doesn't natively support scrolling events such as volume control, you can handle scroll events yourself.

// VolumeScreen.kt

val focusRequester: FocusRequester = remember { FocusRequester() }

Column(
    modifier = Modifier
        .fillMaxSize()
        .onRotaryScrollEvent {
            // handle rotary scroll events
            true
        }
        .focusRequester(focusRequester)
        .focusable(),
) { ... }

Create a custom state managed in view model, and a custom callback that is used to process rotary scroll events.

// 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)
    }
}

For the sake of simplicity, the preceding example uses pixel values that, if actually used are likely to be overly sensitive.

Use the callback once you receive the events, as shown in the following snippet.

val focusRequester: FocusRequester = remember { FocusRequester() }
val volumeState by volumeViewModel.volumeState.collectAsState()

Column(
    modifier = Modifier
        .fillMaxSize()
        .onRotaryScrollEvent {
            volumeViewModel
                .onVolumeChangeByScroll(it.verticalScrollPixels)
            true
        }
        .focusRequester(focusRequester)
        .focusable(),
) { ... }

Jetpack Compose is Android's recommended modern toolkit for building native UI. It simplifies and accelerates UI development on Android. Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs.

Updated Mar 24, 2025

Learn how to develop your apps to support keyboard and pointing devices, such as mouse and trackpad, with Compose.

Updated Jul 26, 2024

In this codelab, you’ll learn how to translate your Compose knowledge to wearables with the new Compose for Wear OS. By the end, you’ll have created both simple and advanced composables in an app for your wrist.

Updated Oct 8, 2024