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, ) { // ... } }
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` // ... } // ... } } }
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)) }, ) // ... } }
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), ) { // ... } }
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), ) }