SurfaceTransformation

interface SurfaceTransformation


Object to be used to apply different transformation to the content and the container (i.e. the background) of the composable.

This interface allows you to customize the appearance of a surface by modifying the container painter and applying visual transformations to the content. In this context, a surface is a container composable that displays content (which could use other Composables such as Icon, Text or Button) as well as a background typically drawn using a painter. This is useful for creating custom effects like scaling, rotation, or applying shaders.

Example usage with the Button:

import androidx.compose.foundation.layout.Column import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.wear.compose.foundation.lazy.TransformingLazyColumn import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.SurfaceTransformation import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.lazy.ResponsiveTransformationSpec import androidx.wear.compose.material3.lazy.TransformationVariableSpec import androidx.wear.compose.material3.lazy.rememberTransformationSpec import androidx.wear.compose.material3.lazy.transformedHeight val transformationSpec =  rememberTransformationSpec(  ResponsiveTransformationSpec.smallScreen(  contentAlpha =  TransformationVariableSpec(  0f,  transformationZoneEnterFraction = 0.4f,  transformationZoneExitFraction = 0.8f,  ),  containerAlpha = TransformationVariableSpec(0.3f),  )  ) TransformingLazyColumn {  items(count = 100) {  Button(  onClick = {},  transformation = SurfaceTransformation(transformationSpec),  modifier = Modifier.transformedHeight(this, transformationSpec),  ) {  Text("Button #$it")  }  } }

Example usage with the Card:

import androidx.compose.foundation.layout.Column import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.wear.compose.foundation.lazy.TransformingLazyColumn import androidx.wear.compose.material3.SurfaceTransformation import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.TitleCard import androidx.wear.compose.material3.lazy.rememberTransformationSpec import androidx.wear.compose.material3.lazy.transformedHeight val transformationSpec = rememberTransformationSpec() var expandedIndex by remember { mutableIntStateOf(-1) } TransformingLazyColumn {  items(count = 100) {  TitleCard(  onClick = { expandedIndex = if (expandedIndex == it) -1 else it },  title = { Text("Card #$it") },  subtitle = { Text("Subtitle #$it") },  transformation = SurfaceTransformation(transformationSpec),  modifier = Modifier.transformedHeight(this, transformationSpec),  ) {  if (it == expandedIndex) {  Text("Expanded content #$it")  }  }  } }

Example of adding support in a custom component:

import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.draw.paint import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.painter.ColorPainter import androidx.compose.ui.unit.dp import androidx.wear.compose.foundation.lazy.TransformingLazyColumn import androidx.wear.compose.material3.SurfaceTransformation import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.lazy.rememberTransformationSpec import androidx.wear.compose.material3.lazy.transformedHeight @Composable fun MyCardComponent(  title: String,  body: String,  transformation: SurfaceTransformation,  modifier: Modifier = Modifier, ) {  Column(  modifier =  modifier  .fillMaxWidth()  .paint(  transformation.createContainerPainter(  ColorPainter(color = Color.Gray),  shape = RoundedCornerShape(16.dp),  )  )  .graphicsLayer { with(transformation) { applyContainerTransformation() } }  .padding(horizontal = 16.dp, vertical = 8.dp)  ) {  Text(title)  Text(body)  } } val transformationSpec = rememberTransformationSpec() TransformingLazyColumn {  items(count = 100) {  MyCardComponent(  "Message #$it",  "This is a body",  transformation = SurfaceTransformation(transformationSpec),  modifier = Modifier.transformedHeight(this, transformationSpec),  )  } }

Summary

Public functions

Unit

Visual transformations to be applied to the container of the item.

Unit

Visual transformations to be applied to the content of the item.

Painter
createContainerPainter(
    painter: Painter,
    shape: Shape,
    border: BorderStroke?
)

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

Public functions

applyContainerTransformation

fun GraphicsLayerScope.applyContainerTransformation(): Unit

Visual transformations to be applied to the container of the item.

This function is called within a GraphicsLayerScope, allowing you to use properties like scaleX, scaleY, rotationZ, alpha, and others to transform the content.

applyContentTransformation

fun GraphicsLayerScope.applyContentTransformation(): Unit

Visual transformations to be applied to the content of the item.

This function is called within a GraphicsLayerScope, allowing you to use properties like scaleX, scaleY, rotationZ, alpha, and others to transform the content.

createContainerPainter

Added in 1.5.0
fun createContainerPainter(
    painter: Painter,
    shape: Shape,
    border: BorderStroke? = null
): Painter

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

This allows the transformation to modify the container painter based on properties like the shape or border. For example, a transformation might apply a gradient that follows the shape of the surface.

Parameters
painter: Painter

The original painter.

shape: Shape

The shape of the content to be used for clipping.

border: BorderStroke? = null

The border to be applied to the container.