以下各節說明如何結合 Modifier.blur、BlurRadiusSpec、BlurStop 和 BlurScope,用於常見的 UI 模式。如要瞭解這些 API,請參閱「在 Compose 中模糊處理」。
模糊處理捲動或可拖曳內容的邊緣
顯示捲動清單、輪轉介面或挑選器時,您可以使用多停點漸進式模糊處理,柔化容器邊緣附近的項目,同時讓使用中的中心區域保持清晰。
淡出捲動清單的頂端和底部邊緣
如要在項目捲動進出垂直清單的可視區域時,柔化項目邊緣,請將含有 BlurStop 項目的 BlurRadiusSpec.verticalGradient 套用至 LazyColumn。在以下範例中,歌詞會逐行捲動,0.42f 和 0.58f 之間的 0.dp 停靠點會讓中央的活動行保持清晰,而靠近頂端和底端邊緣的行則會逐漸模糊:
@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, ) { // ... } }
淡出水平控制項的左右邊緣
同樣地,如要將焦點移至可水平捲動或拖曳的元件中心 (例如滾輪挑選器、輪轉介面或測量刻度),請套用 BlurRadiusSpec.horizontalGradient 和 BlurStop 項目。在下列可拖曳的體重計中,左右邊緣會模糊,而中心指標針附近的刻度和數字則保持完全清晰:
@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` // ... } // ... } } }
使用 linearGradient 建立對角模糊效果
BlurRadiusSpec.linearGradient 會沿著圖層座標空間中 start 和 end DpOffset 值之間的線段,改變模糊半徑。在 Modifier.blur lambda 區塊中,您可以讀取 BlurScope.size,從左上角到右下角對主頁橫幅套用對角漸進模糊效果,讓左上角的主體保持完全清晰,同時逐漸模糊疊加文字後方的右下角區域:
@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)) }, ) // ... } }

使用 radialGradient 建立焦點精選
BlurRadiusSpec.radialGradient 會從焦點向外改變模糊半徑,建立圓形聚光燈效果。將 center 定義為 DpOffset,並將 fallOffRadius 定義為從 center 到達 endRadius 的 Dp 距離。如果將 center 設為 DpOffset.Unspecified,漸層會以可組合項為中心;如果將 fallOffRadius 設為 Dp.Unspecified,則預設為圖層較小尺寸的一半。
舉例來說,在一段文字上套用 BlurRadiusSpec.radialGradient,並根據指標拖曳事件更新 center,使用者就能在段落中拖曳圓形閱讀聚光燈,同時模糊周圍文字,如以下範例所示:
@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), ) { // ... } }
使用著色器建立自訂模糊遮罩
如果空間模糊分布較為複雜,超出線性或放射狀漸層,例如重複圖案、任意形狀或程序雜訊,請將自訂 Shader (例如 AGSL RuntimeShader) 傳遞至 BlurRadiusSpec.shader。著色器會從左上角原點開始,以圖層像素座標進行評估,其取樣的 Alpha 色板 (0..1) 會縮放 maxRadius。
使用 remember 可組合函式建立著色器和 BlurRadiusSpec.shader 設定一次,以便在重組時重複使用單一例項。Compose 會在每次解析時,使用圖層大小叫用設定區塊,您可以在這裡設定與大小相關的統一變數:
@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), ) }