TransformationSpec

interface TransformationSpec

Known direct subclasses
ResponsiveTransformationSpec

Version of TransformationSpec that supports variable screen sizes.


Defines visual transformations on the items of a TransformingLazyColumn.

When using this API, users need to make similar changes between all of the functions. For example, if getTransformedHeight returns half of the size of the item, then transformation functions should do the same, scaling or cropping the item.

getTransformedHeight is called first, then the painter would be created and then container and content transformations are applied.

This shows how to create a custom transformation spec for the TransformingLazyColumn.

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.GraphicsLayerScope
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.unit.dp
import androidx.wear.compose.foundation.lazy.TransformingLazyColumn
import androidx.wear.compose.foundation.lazy.TransformingLazyColumnItemScrollProgress
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.lazy.TransformationSpec
import androidx.wear.compose.material3.lazy.rememberResponsiveTransformationSpec

val transformationSpec = rememberResponsiveTransformationSpec()
val morphingTransformationSpec =
    object : TransformationSpec by transformationSpec {
        override fun GraphicsLayerScope.applyContainerTransformation(
            scrollProgress: TransformingLazyColumnItemScrollProgress
        ) {
            with(transformationSpec) { applyContainerTransformation(scrollProgress) }
            rotationX = (scrollProgress.topOffsetFraction - 0.5f).coerceIn(0f..1f) * 270f
        }
    }

TransformingLazyColumn(
    contentPadding = PaddingValues(20.dp),
    modifier = Modifier.background(Color.Black)
) {
    items(count = 100) { index ->
        TransformExclusion {
            Button(
                onClick = {},
                modifier =
                    Modifier.fillMaxWidth()
                        .transformedHeight(morphingTransformationSpec::getTransformedHeight)
                        .graphicsLayer {
                            with(morphingTransformationSpec) {
                                applyContainerTransformation(scrollProgress)
                            }
                        },
            ) {
                Text(
                    "Item $index",
                    modifier =
                        Modifier.graphicsLayer {
                            with(morphingTransformationSpec) {
                                applyContentTransformation(scrollProgress)
                            }
                        }
                )
            }
        }
    }
}

This shows how to apply the TransformationSpec to custom component inside TransformingLazyColumn.

import androidx.compose.foundation.background
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.unit.dp
import androidx.wear.compose.foundation.lazy.TransformingLazyColumn
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ButtonGroup
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.lazy.TransformationSpec
import androidx.wear.compose.material3.lazy.rememberResponsiveTransformationSpec

// Use the spec derived from default small and large screen specs.
val transformationSpec = rememberResponsiveTransformationSpec()

TransformingLazyColumn(
    contentPadding = PaddingValues(20.dp),
    modifier = Modifier.background(Color.Black)
) {
    items(count = 100) {
        TransformExclusion {
            val interactionSource1 = remember { MutableInteractionSource() }
            val interactionSource2 = remember { MutableInteractionSource() }

            ButtonGroup(
                modifier =
                    Modifier.fillMaxWidth()
                        .graphicsLayer {
                            with(transformationSpec) {
                                applyContainerTransformation(scrollProgress)
                            }
                        }
                        .transformedHeight(transformationSpec::getTransformedHeight)
            ) {
                Button(
                    onClick = {},
                    modifier = Modifier.animateWidth(interactionSource1),
                    interactionSource = interactionSource1,
                ) {
                    Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
                        Text(
                            "L",
                            modifier =
                                Modifier.graphicsLayer {
                                    with(transformationSpec) {
                                        applyContentTransformation(scrollProgress)
                                    }
                                }
                        )
                    }
                }
                Button(
                    onClick = {},
                    modifier = Modifier.animateWidth(interactionSource2),
                    interactionSource = interactionSource2,
                ) {
                    Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
                        Text(
                            "R",
                            modifier =
                                Modifier.graphicsLayer {
                                    with(transformationSpec) {
                                        applyContentTransformation(scrollProgress)
                                    }
                                }
                        )
                    }
                }
            }
        }
    }
}

Summary

Public functions

Unit

Visual transformations to be applied to the container of the item as it scrolls.

Unit

Visual transformations to be applied to the content of the item as it scrolls.

Painter
TransformedPainterScope.createTransformedPainter(
    painter: Painter,
    shape: Shape,
    border: BorderStroke?
)

Returns a new painter to be used instead of painter which should react on a transformation.

Int
getTransformedHeight(
    measuredHeight: Int,
    scrollProgress: TransformingLazyColumnItemScrollProgress
)

Calculates the transformed height to be passed into TransformingLazyColumnItemScope.transformedHeight based on the parameters for the spec.

Public functions

applyContainerTransformation

fun GraphicsLayerScope.applyContainerTransformation(
    scrollProgress: TransformingLazyColumnItemScrollProgress
): Unit

Visual transformations to be applied to the container of the item as it scrolls.

Parameters
scrollProgress: TransformingLazyColumnItemScrollProgress

The scroll progress of the item.

applyContentTransformation

fun GraphicsLayerScope.applyContentTransformation(
    scrollProgress: TransformingLazyColumnItemScrollProgress
): Unit

Visual transformations to be applied to the content of the item as it scrolls.

Parameters
scrollProgress: TransformingLazyColumnItemScrollProgress

The scroll progress of the item.

createTransformedPainter

fun TransformedPainterScope.createTransformedPainter(
    painter: Painter,
    shape: Shape,
    border: BorderStroke?
): Painter

Returns a new painter to be used instead of painter which should react on a transformation.

Parameters
painter: Painter

The painter to be transformed. This is the original Painter the component was trying to use.

shape: Shape

The shape of the item's background.

border: BorderStroke?

The border of the item's background.

getTransformedHeight

fun getTransformedHeight(
    measuredHeight: Int,
    scrollProgress: TransformingLazyColumnItemScrollProgress
): Int

Calculates the transformed height to be passed into TransformingLazyColumnItemScope.transformedHeight based on the parameters for the spec.

Parameters
measuredHeight: Int

The height in pixels of the item returned during measurement.

scrollProgress: TransformingLazyColumnItemScrollProgress

The scroll progress of the item.