Häufige Anwendungsfälle für die Unkenntlichmachung

In den folgenden Abschnitten wird gezeigt, wie Sie Modifier.blur, BlurRadiusSpec, BlurStop und BlurScope für gängige UI-Muster kombinieren. Eine Einführung in diese APIs finden Sie unter Weichzeichnen in Compose.

Ränder von scrollbaren oder ziehbaren Inhalten weichzeichnen

Wenn Sie eine scrollbare Liste, ein Karussell oder eine Auswahl anzeigen, können Sie mit progressiven Unschärfen mit mehreren Stopps Elemente in der Nähe der Containerränder weicher darstellen, während der aktive mittlere Bereich scharf bleibt.

Oberen und unteren Rand einer scrollbaren Liste ausblenden

Wenn Sie Elemente beim Scrollen in den und aus dem Darstellungsbereich einer vertikalen Liste weicher darstellen möchten, wenden Sie BlurRadiusSpec.verticalGradient mit BlurStop-Einträgen auf die LazyColumn an. Im folgenden Beispiel, in dem Songtexte Zeile für Zeile gescrollt werden, sorgen die 0.dp-Stopps zwischen 0.42f und 0.58f dafür, dass die aktive Zeile in der Mitte scharf bleibt, während die Zeilen am oberen und unteren Rand zunehmend unscharf werden:

@Composable
fun SongListTopBottomBlurExample(lyrics: List<String>) {
    // ...
    LazyColumn(
        state = listState,
        flingBehavior = flingBehavior,
        modifier = Modifier
            .width(330.dp)
            .height(480.dp)
            .padding(horizontal = 24.dp)
            .blur(
                blurRadiusSpec = BlurRadiusSpec.verticalGradient(
                    stops = listOf(
                        BlurStop(fraction = 0.00f, radius = 18.dp), // Heavily blurred top edge
                        BlurStop(fraction = 0.24f, radius = 8.dp), // Soft upper transition
                        BlurStop(fraction = 0.42f, radius = 0.dp), // Sharp center focus starts
                        BlurStop(fraction = 0.58f, radius = 0.dp), // Sharp center focus ends
                        BlurStop(fraction = 0.76f, radius = 8.dp), // Soft lower transition
                        BlurStop(fraction = 1.00f, radius = 18.dp), // Heavily blurred bottom edge
                    ),
                ),
                edgeTreatment = BlurredEdgeTreatment.Unbounded,
            ),
        contentPadding = PaddingValues(vertical = 36.dp),
        verticalArrangement = Arrangement.spacedBy(26.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        // ...
    }
}

Abbildung 1. Eine vertikale Liste mit Songtextzeilen, bei der die oberen und unteren Zeilen unscharf sind, während die mittlere Zeile klar ist.

Linken und rechten Rand eines horizontalen Steuerelements ausblenden

Wenn Sie den Fokus auf die Mitte einer horizontal scrollbaren oder ziehbaren Komponente wie einer Rad-Auswahl, eines Karussells oder einer Messskala lenken möchten, wenden Sie BlurRadiusSpec.horizontalGradient mit BlurStop-Einträgen an. In der folgenden ziehbaren Gewichtsskala werden die linken und rechten Ränder weicher, während die Teilstriche und Zahlen in der Nähe der mittleren Anzeigennadel vollständig scharf bleiben:

@Composable
fun HorizontalScaleBlurExample() {
    var selectedValue by remember { mutableFloatStateOf(65.0f) }
    val animatedValue by animateFloatAsState(
        targetValue = selectedValue,
        animationSpec = tween(durationMillis = 900, easing = FastOutSlowInEasing),
        label = "horizontalScaleSmoothScroll",
    )
    Column(
        modifier = Modifier
            .width(340.dp)
            .background(Color(0xFF0F172A), RoundedCornerShape(24.dp))
            .padding(vertical = 24.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Text(
            text = "${(animatedValue * 10).roundToInt() / 10.0} kg",
            color = Color.White,
            fontSize = 44.sp,
            fontWeight = FontWeight.Black,
        )
        Spacer(Modifier.height(16.dp))
        Box(
            // ...
        ) {
            // Ruler ticks blurred at the left and right edges, sharp at center
            Canvas(
                modifier = Modifier
                    .fillMaxSize()
                    .blur(
                        blurRadiusSpec = BlurRadiusSpec.horizontalGradient(
                            stops = listOf(
                                BlurStop(fraction = 0.00f, radius = 14.dp),
                                BlurStop(fraction = 0.28f, radius = 0.dp),
                                BlurStop(fraction = 0.72f, radius = 0.dp),
                                BlurStop(fraction = 1.00f, radius = 14.dp),
                            ),
                        ),
                        edgeTreatment = BlurredEdgeTreatment.Unbounded,
                    ),
            ) {
                // Draw horizontal ruler ticks offset by `animatedValue`
                // ...
            }
            // ...
        }
    }
}

Abbildung 2. Ein horizontales Lineal-Widget mit unscharfen Markierungen an den Rändern und scharfen Markierungen in der Nähe der Anzeigenadel.

Diagonale Unschärfe mit linearGradient erstellen

BlurRadiusSpec.linearGradient variiert den Unschärferadius entlang eines Liniensegments zwischen start- und end-DpOffset-Werten im Koordinatenraum der Ebene. Im Lambda-Block Modifier.blur können Sie BlurScope.size lesen, um eine diagonale progressive Unschärfe über ein Hero-Image von der oberen linken Ecke zur unteren rechten Ecke auszuführen. Dabei bleibt das Motiv oben links vollständig scharf, während der Bereich unten rechts hinter dem eingeblendeten Text progressiv unscharf wird:

@Composable
fun DiagonalLinearBlurCardExample() {
    Box(
        modifier = Modifier
            .wrapContentSize()
            .background(Color(0xFFF8FAFC))
            .padding(10.dp),
    ) {
        Image(
            painter = painterResource(id = R.drawable.dog),
            contentDescription = stringResource(id = R.string.dog_content_description),
            contentScale = ContentScale.Crop,
            modifier = Modifier
                .size(width = 300.dp, height = 380.dp)
                .blur {
                    blurRadiusSpec = BlurRadiusSpec.linearGradient(
                        start = DpOffset(0.dp, 0.dp),
                        end = DpOffset(size.width, size.height),
                        stops = listOf(
                            BlurStop(fraction = 0.00f, radius = 0.dp),
                            BlurStop(fraction = 0.50f, radius = 0.dp),
                            BlurStop(fraction = 0.75f, radius = 14.dp),
                            BlurStop(fraction = 1.00f, radius = 28.dp),
                        ),
                    )
                    edgeTreatment = BlurredEdgeTreatment(RoundedCornerShape(24.dp))
                },
        )
        // ...
    }
}

Ein Hundeporträt, das oben links scharf ist und nach unten rechts hin immer unschärfer wird. Über dem unscharfen Bereich liegt ein scharfer weißer Titel- und Untertiteltext.
Abbildung 3: Ein Hundeporträt, das oben links scharf ist und nach unten rechts immer unschärfer wird. Über dem unscharfen Bereich liegt ein scharfer weißer Titel- und Untertiteltext.

Fokus-Spotlight mit radialGradient erstellen

BlurRadiusSpec.radialGradient erzeugt einen kreisförmigen Spotlight-Effekt, indem der Unschärferadius von einem Fokuspunkt nach außen variiert wird. Definieren Sie center als DpOffset und fallOffRadius als die Dp-Entfernung von center, bei der endRadius erreicht wird. Wenn Sie center als DpOffset.Unspecified belassen, wird der Farbverlauf auf der zusammensetzbaren Funktion zentriert. Wenn Sie fallOffRadius als Dp.Unspecified belassen, wird standardmäßig die Hälfte der kleineren Dimension der Ebene verwendet.

Wenn Sie beispielsweise BlurRadiusSpec.radialGradient auf einen Textabschnitt anwenden und center über Pointer-Drag-Ereignisse aktualisieren, kann der Nutzer einen kreisförmigen Lesespotlight über den Absatz ziehen, während der umgebende Text unscharf dargestellt wird. Das folgende Beispiel zeigt, wie das funktioniert:

@Composable
fun RadialSpotlightTextExample() {
    var touchOffset by remember { mutableStateOf(Offset.Unspecified) }
    Box(
        modifier = Modifier
            .size(width = 330.dp, height = 340.dp)
            .background(Color(0xFF0F172A), RoundedCornerShape(20.dp))
            .pointerInput(Unit) {
                detectDragGestures(
                    onDragStart = { offset -> touchOffset = offset },
                    onDrag = { change, _ -> touchOffset = change.position },
                )
            }
            .blur {
                val spotlightCenter = if (touchOffset.isSpecified) {
                    DpOffset(touchOffset.x.toDp(), touchOffset.y.toDp())
                } else {
                    DpOffset(x = size.width / 2, y = size.height / 2)
                }
                blurRadiusSpec = BlurRadiusSpec.radialGradient(
                    startRadius = 0.dp,
                    endRadius = 10.dp,
                    center = spotlightCenter,
                    fallOffRadius = 215.dp,
                )
                edgeTreatment = BlurredEdgeTreatment(RoundedCornerShape(20.dp))
            }
            .padding(22.dp),
    ) {
        // ...
    }
}

Abbildung 4. Ein Textabsatz mit einem kreisförmigen Bereich mit scharfem Text um den Mauszeiger, der zum Rand des Kreises hin immer unschärfer wird.

Benutzerdefinierte Unschärfemaske mit einem Shader erstellen

Für komplexe räumliche Unschärfeverteilungen, die über lineare oder radiale Farbverläufe hinausgehen, z. B. sich wiederholende Muster, beliebige Formen oder prozedurales Rauschen, übergeben Sie einen benutzerdefinierten Shader, z. B. einen AGSL RuntimeShader, an BlurRadiusSpec.shader. Der Shader wird in Ebenenpixelkoordinaten vom Ursprung oben links ausgewertet und sein abgetasteter Alphakanal (0..1) skaliert maxRadius.

Erstellen Sie den Shader und die BlurRadiusSpec.shader-Konfiguration einmal mit der zusammensetzbaren Funktion remember, damit eine einzelne Instanz bei Neuzusammensetzungen wiederverwendet wird. Compose ruft den Konfigurationsblock mit der Ebenengröße bei jeder Auflösung auf. Hier legen Sie größenabhängige Uniforms fest:

@RequiresApi(Build.VERSION_CODES.TIRAMISU)
@Composable
fun ShaderBlurExample() {
    // Creates 6 diagonal frosted-glass bands across the image.
    val maskShader = remember {
        RuntimeShader(
            """
            uniform float2 size;
            half4 main(float2 coord) {
                float2 uv = coord / size;
                float band = smoothstep(0.4, 0.6, fract((uv.x + uv.y) * 3.0));
                return half4(0.0, 0.0, 0.0, half(band));
            }
            """.trimIndent(),
        )
    }
    val maskBlurSpec = remember(maskShader) {
        BlurRadiusSpec.shader(maxRadius = 24.dp) { sizePx ->
            maskShader.setFloatUniform("size", sizePx.width, sizePx.height)
            maskShader
        }
    }
    Image(
        painter = painterResource(id = R.drawable.dog),
        contentDescription = stringResource(id = R.string.dog_content_description),
        contentScale = ContentScale.Crop,
        modifier = Modifier
            .size(150.dp)
            .blur(blurRadiusSpec = maskBlurSpec),
    )
}

Ein Bild eines Hundes mit diagonalen Milchglas-Unschärfebändern, die durch eine benutzerdefinierte Shader-Maske erzeugt werden.
Abbildung 5. Ein Bild eines Hundes mit diagonalen Milchglas-Unschärfebändern, die durch eine benutzerdefinierte Shader-Maske erzeugt werden.