Le sezioni seguenti mostrano come combinare Modifier.blur, BlurRadiusSpec, BlurStop e BlurScope per i pattern UI comuni. Per un'introduzione a queste API, consulta Sfocatura in Compose.
Sfoca i bordi dei contenuti scorrevoli o trascinabili
Quando mostri un elenco a scorrimento, un carosello o un selettore, puoi utilizzare sfocature progressive con più punti di interruzione per ammorbidire gli elementi vicino ai bordi del container, mantenendo al contempo la regione centrale attiva ben a fuoco.
Dissolvenza dei bordi superiore e inferiore di un elenco a scorrimento
Per ammorbidire gli elementi quando scorrono dentro e fuori dall'area visibile di un elenco verticale, applica BlurRadiusSpec.verticalGradient con voci BlurStop a LazyColumn. Nell'esempio seguente, che scorre il testo di un brano riga per riga,
i punti di interruzione 0.dp tra 0.42f e 0.58f mantengono la riga attiva al centro
nitida, mentre le righe verso i bordi superiore e inferiore sfocano progressivamente:
@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, ) { // ... } }
Sfuma i bordi sinistro e destro di un controllo orizzontale
Allo stesso modo, per attirare l'attenzione sul centro di un componente scorrevole o trascinabile in orizzontale, come un selettore a rotella, un carosello o una scala di misurazione, applica BlurRadiusSpec.horizontalGradient con voci BlurStop. Nella seguente bilancia trascinabile, i bordi sinistro e destro sono sfocati, mentre i segni di graduazione e i numeri vicino alla lancetta dell'indicatore centrale rimangono completamente nitidi:
@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` // ... } // ... } } }
Crea una sfocatura diagonale con linearGradient
BlurRadiusSpec.linearGradient varia il raggio di sfocatura lungo un segmento di linea tra i valori start e end DpOffset nello spazio delle coordinate del livello.
All'interno del blocco lambda Modifier.blur, puoi leggere BlurScope.size per eseguire una sfocatura progressiva diagonale su un'immagine hero dall'angolo in alto a sinistra all'angolo in basso a destra, mantenendo il soggetto in alto a sinistra completamente nitido e sfocando progressivamente la regione in basso a destra dietro il testo sovrapposto:
@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)) }, ) // ... } }
Crea un momento di concentrazione con radialGradient
BlurRadiusSpec.radialGradient crea un effetto di luce circolare variando il raggio di sfocatura verso l'esterno da un punto focale. Definisci center come DpOffset e fallOffRadius come distanza Dp da center alla quale viene raggiunto endRadius. Se lasci center come DpOffset.Unspecified, il gradiente è centrato sul composable, mentre se lasci fallOffRadius come Dp.Unspecified, il valore predefinito è la metà della dimensione più piccola del livello.
Ad esempio, l'applicazione di BlurRadiusSpec.radialGradient su un passaggio di testo e l'aggiornamento di center dagli eventi di trascinamento del puntatore consentono all'utente di trascinare un riflettore di lettura circolare sul paragrafo sfocando il testo circostante, come mostrato nell'esempio seguente:
@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), ) { // ... } }
Crea una maschera di sfocatura personalizzata con uno shader
Per distribuzioni di sfocatura spaziale complesse che vanno oltre i gradienti lineari o radiali, come pattern ripetuti, forme arbitrarie o rumore procedurale, passa un Shader personalizzato, come un AGSL RuntimeShader, a BlurRadiusSpec.shader. Lo shader viene valutato nelle coordinate dei pixel del livello dall'origine in alto a sinistra e il suo canale alfa campionato (0..1) scala maxRadius.
Crea lo shader e la configurazione BlurRadiusSpec.shader una volta utilizzando la funzione componibile remember, in modo che una singola istanza venga riutilizzata nelle ricomposizioni. Compose richiama il blocco di configurazione con le dimensioni del livello a ogni risoluzione, ovvero dove imposti le uniformi dipendenti dalle dimensioni:
@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), ) }