Configuration parameters for the size change (expand/shrink) effect of an EnterTransition or ExitTransition.

import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.tween
import androidx.compose.animation.core.updateTransition
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.size
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.ColorMatrix
import androidx.compose.ui.graphics.Paint
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.unit.dp

var visible by remember { mutableStateOf(true) }

// A custom transition container that uses enter/exit transition configurations to build custom
// transition behavior.
@Composable
fun customTransitionBox(
    enter: EnterTransition,
    exit: ExitTransition,
    content: @Composable () -> Unit,
) {
    val transition = updateTransition(visible, label = "CustomTransitionBox")

    // Use the fade config to animate alpha
    val fadeConfig = if (transition.targetState) enter.config.fade else exit.config.fade

    val alpha by
        transition.animateFloat(
            transitionSpec = { fadeConfig?.animationSpec ?: tween() },
            label = "alpha",
        ) { state ->
            if (state) 1f else fadeConfig?.alpha ?: 0f
        }

    Box(
        modifier =
            Modifier.graphicsLayer { this.alpha = alpha }
                .drawWithContent {
                    // Apply custom saturation fade using alpha
                    val matrix = ColorMatrix().apply { setToSaturation(alpha) }
                    drawIntoCanvas { canvas ->
                        val paint =
                            Paint().apply { colorFilter = ColorFilter.colorMatrix(matrix) }
                        canvas.saveLayer(Rect(Offset.Zero, size), paint)
                        drawContent()
                        canvas.restore()
                    }
                }
    ) {
        content()
    }
}

Column {
    Button(onClick = { visible = !visible }) { Text("Toggle visibility") }

    customTransitionBox(
        fadeIn(animationSpec = tween(durationMillis = 1000), initialAlpha = 0f),
        fadeOut(animationSpec = tween(durationMillis = 1000), targetAlpha = 0f),
    ) {
        Box(Modifier.size(200.dp).background(Color.Blue))
    }
}

Summary

Public functions

open operator Boolean
equals(other: Any?)
Cmn
open Int
Cmn
open String
Cmn

Public properties

Alignment

The Alignment used to align the content inside the changing boundary.

Cmn
FiniteAnimationSpec<IntSize>

The FiniteAnimationSpec used for the size animation.

Cmn
Boolean

If true, the content will be clipped to the animated size boundary.

Cmn
(fullSize: IntSize) -> IntSize

Lambda that calculates the initial size for EnterTransition, or target size for ExitTransition based on the full container size.

Cmn

Public functions

equals

open operator fun equals(other: Any?): Boolean

hashCode

open fun hashCode(): Int

toString

open fun toString(): String

Public properties

alignment

val alignmentAlignment

The Alignment used to align the content inside the changing boundary.

animationSpec

val animationSpecFiniteAnimationSpec<IntSize>

The FiniteAnimationSpec used for the size animation.

clip

val clipBoolean

If true, the content will be clipped to the animated size boundary.

size

val size: (fullSize: IntSize) -> IntSize

Lambda that calculates the initial size for EnterTransition, or target size for ExitTransition based on the full container size.