---
title: "TransformationSpec"
description: "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].


This shows how to apply different [androidx.compose.ui.graphics.CompositingStrategy] with
[TransformationSpec] for the [TransformingLazyColumn].


This shows how to apply the [TransformationSpec] to custom component inside
[TransformingLazyColumn]."
type: "interface"
---

<div class='type'>Interface</div>


<a id='references'></a>

<div class='sourceset sourceset-android'>Android</div>



```kotlin
public interface TransformationSpec
```


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`.


This shows how to apply different `androidx.compose.ui.graphics.CompositingStrategy` with
`TransformationSpec` for the `TransformingLazyColumn`.


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


## Functions

```kotlin
public 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 | The height in pixels of the item returned during measurement. |
| scrollProgress | The scroll progress of the item. |



```kotlin
public fun GraphicsLayerScope.applyContentTransformation(
        scrollProgress: TransformingLazyColumnItemScrollProgress
    )
```


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

#### Parameters

| | |
| --- | --- |
| scrollProgress | The scroll progress of the item. |



```kotlin
public fun GraphicsLayerScope.applyContainerTransformation(
        scrollProgress: TransformingLazyColumnItemScrollProgress
    )
```


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

#### Parameters

| | |
| --- | --- |
| scrollProgress | The scroll progress of the item. |



```kotlin
public fun TransformedContainerPainterScope.createTransformedContainerPainter(
        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 | The painter to be transformed. This is the original `Painter` the component was trying to use. |
| shape | The shape of the item's container. |
| border | The border of the item's container. |




## Code Examples

### CustomCompositingStrategyTransformationSpecSample
```kotlin
@Composable
@Preview
fun CustomCompositingStrategyTransformationSpecSample() {
    val transformationSpec = rememberTransformationSpec()
    TransformingLazyColumn(
        contentPadding = PaddingValues(20.dp),
        modifier = Modifier.background(Color.Black),
    ) {
        items(count = 100) { index ->
            Button(
                onClick = {},
                modifier =
                    Modifier.fillMaxWidth()
                        .transformedHeight(this, transformationSpec)
                        .graphicsLayer {
                            with(transformationSpec) {
                                applyContainerTransformation(scrollProgress)
                            }
                            // Using CompositingStrategy.ModulateAlpha can provide better
                            // performance when a container transformation involves alpha rendering,
                            // as it avoids an extra offscreen buffer.
                            //
                            // However, care must be taken with overlapping or transparent content
                            // inside the container. If the content itself uses alpha, ModulateAlpha
                            // can lead to multiple, incorrect alpha blending with the background
                            // (double-blending artifacts).
                            //
                            // To prevent this, the content's drawing layer must explicitly use
                            // CompositingStrategy.Offscreen to ensure internal elements are
                            // correctly pre-blended before the outer ModulateAlpha is applied.
                            compositingStrategy = ModulateAlpha
                        },
            ) {
                Text(
                    text = "Item $index",
                    modifier =
                        Modifier.graphicsLayer {
                            // Ensure content layer uses CompositingStrategy.Offscreen when
                            // container uses CompositingStrategy.ModulateAlpha.
                            // This composition is required to guarantee correct visual blending of
                            // content that contains internal alpha or complex blending.
                            // compositingStrategy is set to CompositingStrategy.Offscreen inside
                            // applyContentTransformation.
                            with(transformationSpec) { applyContentTransformation(scrollProgress) }
                        },
                )
            }
        }
    }
}
```

### CustomTransformationSpecSample
```kotlin
@Composable
@Preview
fun CustomTransformationSpecSample() {
    val transformationSpec = rememberTransformationSpec()
    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 ->
            Button(
                onClick = {},
                modifier =
                    Modifier.fillMaxWidth()
                        .transformedHeight(this, morphingTransformationSpec)
                        .graphicsLayer {
                            with(morphingTransformationSpec) {
                                applyContainerTransformation(scrollProgress)
                            }
                        },
            ) {
                Text(
                    "Item $index",
                    modifier =
                        Modifier.graphicsLayer {
                            with(morphingTransformationSpec) {
                                applyContentTransformation(scrollProgress)
                            }
                        },
                )
            }
        }
    }
}
```

### TransformationSpecButtonRowSample
```kotlin
@Composable
@Preview
fun TransformationSpecButtonRowSample() {
    // Use the spec derived from default small and large screen specs.
    val transformationSpec = rememberTransformationSpec()
    TransformingLazyColumn(
        contentPadding = PaddingValues(20.dp),
        modifier = Modifier.background(Color.Black),
    ) {
        items(count = 100) {
            val interactionSource1 = remember { MutableInteractionSource() }
            val interactionSource2 = remember { MutableInteractionSource() }
            ButtonGroup(
                modifier =
                    Modifier.fillMaxWidth()
                        .graphicsLayer {
                            with(transformationSpec) {
                                applyContainerTransformation(scrollProgress)
                            }
                        }
                        .transformedHeight(this, transformationSpec)
            ) {
                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)
                                    }
                                },
                        )
                    }
                }
            }
        }
    }
}
```

