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 }
)
}