Bagian berikut menunjukkan cara menggabungkan Modifier.blur,
BlurRadiusSpec, BlurStop, dan BlurScope untuk pola UI
umum. Untuk pengantar API ini, lihat Membuat blur di Compose.
Memburamkan tepi konten yang dapat di-scroll atau ditarik
Saat menampilkan daftar scroll, carousel, atau pemilih, Anda dapat menggunakan blur progresif multi-stop untuk melembutkan item di dekat tepi penampung sambil menjaga area tengah yang aktif tetap fokus.
Memudarkan tepi atas dan bawah daftar scroll
Untuk memperhalus item saat di-scroll ke dalam dan ke luar area pandang daftar vertikal,
terapkan BlurRadiusSpec.verticalGradient dengan entri BlurStop ke
LazyColumn. Dalam contoh berikut, yang men-scroll lirik lagu baris demi baris,
pemberhentian 0.dp antara 0.42f dan 0.58f membuat baris aktif di tengah
tetap tajam, sementara baris di tepi atas dan bawah semakin buram:
@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, ) { // ... } }
Memudarkan tepi kiri dan kanan kontrol horizontal
Demikian pula, untuk menarik fokus ke tengah komponen yang dapat di-scroll atau
ditarik secara horizontal, seperti pemilih roda, carousel, atau skala pengukuran,
terapkan BlurRadiusSpec.horizontalGradient dengan entri BlurStop. Pada
timbangan berat yang dapat ditarik berikut, tepi kiri dan kanan menjadi buram, sedangkan
garis dan angka di dekat jarum indikator tengah tetap terlihat tajam:
@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` // ... } // ... } } }
Membuat blur diagonal dengan linearGradient
BlurRadiusSpec.linearGradient memvariasikan radius blur di sepanjang segmen garis
antara nilai start dan end DpOffset di ruang koordinat lapisan.
Di dalam blok lambda Modifier.blur, Anda dapat membaca BlurScope.size untuk menjalankan
blur progresif diagonal di seluruh banner besar dari sudut kiri atas ke
sudut kanan bawah, sehingga subjek di kiri atas tetap tajam sepenuhnya, sekaligus
membuat blur wilayah kanan bawah di belakang teks overlay secara progresif:
@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)) }, ) // ... } }
Membuat sorotan fokus dengan radialGradient
BlurRadiusSpec.radialGradient menciptakan efek sorotan melingkar dengan memvariasikan
radius blur ke luar dari titik fokus. Tentukan center sebagai DpOffset dan
fallOffRadius sebagai jarak Dp dari center tempat endRadius
tercapai. Jika Anda membiarkan center sebagai DpOffset.Unspecified, gradien akan
dipusatkan pada composable, dan jika Anda membiarkan fallOffRadius sebagai
Dp.Unspecified, gradien akan ditetapkan secara default ke setengah dimensi lapisan yang lebih kecil.
Misalnya, menerapkan BlurRadiusSpec.radialGradient pada bagian teks
dan memperbarui center dari peristiwa tarik pointer memungkinkan pengguna menarik sorotan
bacaan melingkar di seluruh paragraf sambil memburamkan teks di sekitarnya, seperti
yang ditunjukkan dalam contoh berikut:
@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), ) { // ... } }
Membuat mask blur kustom dengan shader
Untuk distribusi blur spasial yang kompleks di luar gradien linear atau radial, seperti
pola berulang, bentuk arbitrer, atau derau prosedural, teruskan
Shader kustom, seperti RuntimeShader AGSL, ke
BlurRadiusSpec.shader. Shader mengevaluasi koordinat piksel lapisan dari
origin kiri atas, dan saluran alfa sampelnya (0..1) menskalakan maxRadius.
Buat shader dan konfigurasi BlurRadiusSpec.shader sekali menggunakan
fungsi composable remember, sehingga satu instance digunakan kembali di seluruh
rekomposisi. Compose memanggil blok konfigurasi dengan ukuran lapisan pada
setiap penyelesaian, yang merupakan tempat Anda menetapkan uniform yang bergantung pada ukuran:
@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), ) }