Lists with Compose for Wear OS


Lists let users select an item from a set of choices on Wear OS devices.

Many Wear OS devices use round screens, which makes it more difficult to see list items that appear near the top and bottom of the screen. For this reason, Compose for Wear OS includes a version of the LazyColumn class called TransformingLazyColumn, which supports scaling and morphing animations. When items move to the edges, they get smaller and fade out.

To apply the recommended scaling and scrolling effects:

  1. Use Modifier.transformedHeight to allow Compose to calculate the height change as the item scrolls through the screen.
  2. Use transformation = SurfaceTransformation(transformationSpec) to apply the visual effects, including scaling down the item contents.
  3. Use a custom TransformationSpec for components that don't take transformation as a parameter such as Text.

The following animation shows how a list element scales and changes shape when approaching the top and bottom of the screen:

The following code snippet shows how to create a list using TransformingLazyColumn layout to create content that looks great on a variety of Wear OS screen sizes.

The snippet also demonstrates the use of the minimumVerticalContentPadding modifier, which you should set on the list items to apply the correct padding at the top and bottom of the list.

To show the scroll indicator, share the columnState between the ScreenScaffold and the TransformingLazyColumn:

val columnState = rememberTransformingLazyColumnState()
val transformationSpec = rememberTransformationSpec()
ScreenScaffold(
    scrollState = columnState
) { contentPadding ->
    TransformingLazyColumn(
        state = columnState,
        contentPadding = contentPadding
    ) {
        item {
            ListHeader(
                modifier = Modifier
                    .fillMaxWidth()
                    .transformedHeight(this, transformationSpec)
                    .minimumVerticalContentPadding(ListHeaderDefaults.minimumTopListContentPadding),
                transformation = SurfaceTransformation(transformationSpec)
            ) {
                Text(text = "Header")
            }
        }
        // ... other items
        item {
            Button(
                modifier = Modifier
                    .fillMaxWidth()
                    .transformedHeight(this, transformationSpec)
                    .minimumVerticalContentPadding(ButtonDefaults.minimumVerticalListContentPadding),
                transformation = SurfaceTransformation(transformationSpec),
                onClick = { /* ... */ },
                icon = {
                    Icon(
                        imageVector = Icons.Default.Build,
                        contentDescription = "build",
                    )
                },
            ) {
                Text(
                    text = "Build",
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis,
                )
            }
        }
    }
}

Add a snap-and-fling effect

If you need to add a snap-and-fling behavior, set the flingBehavior parameter to TransformingLazyColumnDefaults.snapFlingBehavior(columnState), as shown in the following code snippet:
val columnState = rememberTransformingLazyColumnState()
ScreenScaffold(scrollState = columnState) {
    TransformingLazyColumn(
        state = columnState,
        flingBehavior = TransformingLazyColumnDefaults.snapFlingBehavior(columnState)
    ) {
        // ...
        // ...
    }
}