Compose Modifier

blur

Draws content blurred with the specified radii.

BlurSample

@Sampled
@Composable
fun BlurSample() {
    Box(
        Modifier.size(300.dp)
            // Blur content allowing the result to extend beyond the bounds of the original content
            .blur(30.dp, edgeTreatment = BlurredEdgeTreatment.Unbounded)
            .background(Color.Red, CircleShape)
    )
}

ImageBlurSample

@Sampled
@Composable
fun ImageBlurSample() {
    Image(
        painter = painterResource(R.drawable.circus),
        contentDescription = "sample blurred image",
        // Blur content within the original bounds, clipping the result to a rounded rectangle
        modifier = Modifier.blur(30.dp, BlurredEdgeTreatment(RoundedCornerShape(5.dp))),
    )
}

ProgressiveBlurSample

@Sampled
@Composable
fun ProgressiveBlurSample() {
    Box(
        Modifier.size(200.dp)
            .background(Brush.verticalGradient(listOf(Color.Red, Color.Blue)))
            // Sharp at the top, increasingly blurred toward the bottom.
            .blur(BlurRadiusSpec.verticalGradient(startRadius = 0.dp, endRadius = 24.dp))
    )
}

AnimatedProgressiveBlurSample

@Sampled
@Composable
fun AnimatedProgressiveBlurSample() {
    var blurred by remember { mutableStateOf(false) }
    val blurRadius by animateDpAsState(if (blurred) 24.dp else 0.dp, label = "blurRadius")
    Box(
        Modifier.size(200.dp)
            .background(Brush.verticalGradient(listOf(Color.Red, Color.Blue)))
            // blurRadius is read inside the draw-time block, so the animation invalidates only the
            // draw phase.
            .blur {
                blurRadiusSpec =
                    BlurRadiusSpec.verticalGradient(startRadius = 0.dp, endRadius = blurRadius)
            }
            .clickable { blurred = !blurred }
    )
}

MultiStopProgressiveBlurSample

@Sampled
@Composable
fun MultiStopProgressiveBlurSample() {
    Box(
        Modifier.size(200.dp)
            .background(Brush.verticalGradient(listOf(Color.Red, Color.Blue)))
            .blur {
                blurRadiusSpec =
                    BlurRadiusSpec.verticalGradient(
                        listOf(
                            BlurStop(fraction = 0f, radius = 0.dp),
                            BlurStop(fraction = 0.5f, radius = 4.dp),
                            BlurStop(fraction = 1f, radius = 24.dp),
                        )
                    )
            }
    )
}

AngledProgressiveBlurSample

@Sampled
@Composable
fun AngledProgressiveBlurSample() {
    // Blur direction in degrees, CSS convention: 0° fades toward the top, positive angles turn
    // clockwise, so 45° fades toward the top-right.
    val angleDegrees = 45f
    Box(
        Modifier.size(width = 240.dp, height = 120.dp)
            .background(Brush.verticalGradient(listOf(Color.Red, Color.Blue)))
            .blur {
                val angle = angleDegrees * PI.toFloat() / 180f
                // Unit direction of increasing blur; y is negated because screen y points down.
                val dirX = sin(angle)
                val dirY = -cos(angle)
                // Half-length of the gradient line that exactly spans the layer at this angle:
                // the layer's corners project onto the line at fractions 0 and 1.
                val width = size.width.value
                val height = size.height.value
                val halfLength = (abs(width * dirX) + abs(height * dirY)) / 2f
                val center = DpOffset((width / 2f).dp, (height / 2f).dp)
                val halfLine = DpOffset((dirX * halfLength).dp, (dirY * halfLength).dp)
                blurRadiusSpec =
                    BlurRadiusSpec.linearGradient(
                        start = center - halfLine,
                        end = center + halfLine,
                        startRadius = 0.dp,
                        endRadius = 16.dp,
                    )
            }
    )
}

RadialProgressiveBlurSample

@Sampled
@Composable
fun RadialProgressiveBlurSample() {
    Box(
        Modifier.size(200.dp)
            .background(Brush.verticalGradient(listOf(Color.Red, Color.Blue)))
            // Sharp at the center, blurred toward the edges (center and extent default to the
            // layer).
            .blur {
                blurRadiusSpec =
                    BlurRadiusSpec.radialGradient(startRadius = 0.dp, endRadius = 24.dp)
            }
    )
}

ShaderProgressiveBlurSample

@Sampled
@Composable
@RequiresApi(33)
fun ShaderProgressiveBlurSample() {
    // A RuntimeShader whose alpha channel is a 0..1 blur intensity over the mask's maxRadius.
    val radiusShader = remember {
        RuntimeShader(
            """
            uniform float2 size;
            half4 main(float2 coord) {
                // alpha is the blur intensity: 0 at the top (sharp) to 1 at the bottom.
                return half4(0.0, 0.0, 0.0, coord.y / max(size.y, 1.0));
            }
            """
                .trimIndent()
        )
    }
    // Hoisted so a single configuration is reused; the block re-runs at each resolve with the
    // current layer size.
    val maskRadius =
        remember(radiusShader) {
            BlurRadiusSpec.shader(maxRadius = 24.dp) { sizePx ->
                radiusShader.setFloatUniform("size", sizePx.width, sizePx.height)
                radiusShader
            }
        }
    Box(
        Modifier.size(200.dp)
            .background(Brush.verticalGradient(listOf(Color.Red, Color.Blue)))
            .blur { blurRadiusSpec = maskRadius }
    )
}

Content updated: