在 Compose 中模糊處理

模糊效果可柔化視覺細節、營造攝影景深,並將焦點吸引至前景 UI 元素。在 Jetpack Compose 中,使用 Modifier.blur 模糊處理可組合項中繪製的內容,包括圖片、形狀、文字和版面配置容器。套用 Modifier.blur 會將可組合項轉譯為獨立的圖形層。

左:原始圖片。中間:整張圖片套用一致的模糊效果。右圖:圖片採用漸進式模糊處理,頂端清晰,底部模糊程度增加。
圖 1. 左:原始圖片。中間:整張圖片套用一致的模糊效果。右:圖片採用漸進式模糊處理,頂端清晰,底部模糊。

視設計目標而定,您可以透過兩種方式調整模糊效果:

  • 統一模糊:在整個可組合項中套用固定的模糊半徑,兩軸的半徑相同,或水平和垂直半徑獨立 (radiusX、radiusY)。
  • 漸進式模糊:使用 BlurRadiusSpec 漸層或自訂 Shader,在可組合項中空間變化模糊半徑。

套用一致的模糊效果

如要在整個可組合項中套用固定模糊效果,請將 Dp 半徑傳遞至 Modifier.blur。傳遞單一 radius 值,沿著水平 (X) 和垂直 (Y) 軸均勻模糊內容:

@Composable
fun UniformBlurExample() {
    Image(
        painter = painterResource(id = R.drawable.dog),
        contentDescription = stringResource(id = R.string.dog_content_description),
        contentScale = ContentScale.Crop,
        modifier = Modifier
            .size(150.dp)
            .blur(
                radius = 8.dp,
                edgeTreatment = BlurredEdgeTreatment(RoundedCornerShape(8.dp)),
            ),
    )
}

一隻狗,水平和垂直軸均勻模糊。
圖 2. 一隻狗,水平和垂直軸均勻模糊。

如要建立方向性動態模糊效果,請將不同的 radiusX 和 radiusY 值傳遞至 Modifier.blur。radiusX 和 radiusY 都必須大於 0.dp,才能套用模糊效果,如以下範例所示:

@Composable
fun DirectionalBlurExample() {
    Image(
        painter = painterResource(id = R.drawable.dog),
        contentDescription = stringResource(id = R.string.dog_content_description),
        contentScale = ContentScale.Crop,
        modifier = Modifier
            .size(150.dp)
            .blur(
                radiusX = 10.dp,
                radiusY = 2.dp,
                edgeTreatment = BlurredEdgeTreatment(RoundedCornerShape(8.dp)),
            ),
    )
}

一隻狗,有強烈的水平動態模糊效果。
圖 3. 正方形圖片,顯示一隻狗,並有強烈的水平動態模糊效果。

套用漸進模糊效果

漸進式模糊處理會改變可組合項的模糊半徑,在清晰和模糊區域之間建立平滑轉場效果。

將 BlurRadiusSpec 傳遞至 Modifier.blur。舉例來說,使用 BlurRadiusSpec.verticalGradient 搭配 startRadius = 0.dp 和 endRadius = 6.dp,可讓圖片頂端保持清晰,並逐漸模糊至底部,如以下範例所示:

@Composable
fun ProgressiveBlurExample() {
    Image(
        painter = painterResource(id = R.drawable.dog),
        contentDescription = stringResource(id = R.string.dog_content_description),
        contentScale = ContentScale.Crop,
        modifier = Modifier
            .size(150.dp)
            .blur(
                // Sharp at the top (0.dp), progressively blurred toward the bottom (6.dp)
                blurRadiusSpec = BlurRadiusSpec.verticalGradient(
                    startRadius = 0.dp,
                    endRadius = 6.dp,
                ),
                edgeTreatment = BlurredEdgeTreatment(RoundedCornerShape(8.dp)),
            ),
    )
}

一隻狗,頂端清晰,底部逐漸模糊。
圖 4. 一張狗的圖片,頂端清晰,底部逐漸模糊。

使用 BlurRadiusSpec 指定模糊漸層

在 BlurRadiusSpec 中,測量單位會以 Dp 設定,並在繪製時自動調整為圖層的大小和顯示密度。空間變化模糊效果在轉換後上限為 150 像素,而 BlurRadiusSpec.uniform 則沒有上限。

下表列出 BlurRadiusSpec 提供的工廠函式:

BlurRadiusSpec 工廠 說明
BlurRadiusSpec.verticalGradient 在圖層中,由上 (0f) 到下 (1f) 垂直平滑變更模糊半徑。
BlurRadiusSpec.horizontalGradient 從左側邊緣 (0f) 到右側邊緣 (1f),水平平滑變更模糊半徑。
BlurRadiusSpec.linearGradient 沿著連接特定 DpOffset 座標的直線,套用方向性模糊轉場效果。
BlurRadiusSpec.radialGradient 從焦點向外擴散模糊效果,直到 fallOffRadius 邊界。
BlurRadiusSpec.uniform 在整個圖層套用均勻的模糊半徑。
BlurRadiusSpec.shader 使用自訂Shader的 Alpha 色版,控制及縮放每個像素的maxRadius。

使用 BlurStop 自訂模糊分布

標準漸層模糊處理會在 0f 和 1f 之間進行線性內插。如要自訂模糊效果在表面的分布情形,例如模糊多個邊緣或保持中間部分完全清晰,請將包含 2 到 16 個 BlurStop 項目的 List<BlurStop> 傳遞至 verticalGradient、horizontalGradient、linearGradient 或 radialGradient。請為每個 BlurStop 項目定義下列項目:

  • fraction:沿著漸層從 0.0f 到 1.0f 的相對位置。系統會自動依分數排序停靠點。
  • radius:在該分數位置套用的模糊半徑 (以 Dp 為單位)。

舉例來說,四個停靠點會模糊處理圖片的頂端和底部邊緣,同時保持中間完全清晰,如以下範例所示:

@Composable
fun MultiStopBlurExample() {
    Image(
        painter = painterResource(id = R.drawable.dog),
        contentDescription = stringResource(id = R.string.dog_content_description),
        contentScale = ContentScale.Crop,
        modifier = Modifier
            .size(150.dp)
            .blur(
                // Blurred at the top and bottom edges, sharp in the middle (0.3f..0.7f)
                blurRadiusSpec = BlurRadiusSpec.verticalGradient(
                    stops = listOf(
                        BlurStop(fraction = 0.0f, radius = 20.dp),
                        BlurStop(fraction = 0.3f, radius = 0.dp),
                        BlurStop(fraction = 0.7f, radius = 0.dp),
                        BlurStop(fraction = 1.0f, radius = 20.dp),
                    ),
                ),
                edgeTreatment = BlurredEdgeTreatment.Unbounded,
            ),
    )
}

一隻狗,頂端和底部邊緣模糊,中間水平條紋清晰對焦。
圖 5. 圖片中有一隻狗,上下邊緣模糊,中間水平帶則清晰對焦。

使用 BlurScope 設定圖層屬性

您可以將設定區塊傳遞至 Modifier.blur { ... },而不是直接傳遞 blurRadiusSpec。這個區塊會在 BlurScope 內執行,可讓您直接存取版面配置密度和下列屬性:

  • size: DpSize:Dp 中模糊圖層的測量寬度和高度,用於定義漸層幾何圖形的座標空間。
  • blurRadiusSpec: BlurRadiusSpec:整個表面的模糊半徑設定。預設值為 BlurRadiusSpec.uniform(0.dp) (不模糊)。
  • edgeTreatment: BlurredEdgeTreatment:用於取樣及裁剪內容邊界外像素的策略。預設值為 BlurredEdgeTreatment.Rectangle。
  • alpha: Float:模糊圖層的不透明度,範圍為 0f..1f。預設為 1f。

由於 BlurScope 區塊會在測量和版面配置後的圖形層階段執行,因此您可以從 size 計算漸層幾何圖形,而不會觸發重組。

使用 BlurredEdgeTreatment 控制邊緣裁剪

由於模糊處理會對模糊半徑內的鄰近像素進行取樣,因此模糊處理的輸出內容會超出原始內容邊界,超出範圍為模糊半徑。BlurredEdgeTreatment 決定如何對原始邊界外的像素進行取樣,以及是否將結果裁剪為特定形狀。

BlurredEdgeTreatment 適用於均勻和漸進式模糊處理:

BlurredEdgeTreatment 行為 輸出內容
BlurredEdgeTreatment.Rectangle (預設) 將模糊處理結果裁剪至原始內容的矩形邊界,並對最接近的邊緣像素進行取樣 (TileMode.Clamp)。 模糊的狗圖片,裁剪成清晰的矩形邊界。
BlurredEdgeTreatment(shape) 將模糊處理結果裁剪至指定的 Shape (例如 RoundedCornerShape(8.dp)),並對最接近的邊緣像素 (TileMode.Clamp) 進行取樣。在形狀邊界處保持模糊處理結果清晰,不會超出原始邊界。 模糊的狗圖片,剪輯成圓角形狀,邊緣銳利。
BlurredEdgeTreatment.Unbounded 不裁剪模糊處理結果 (TileMode.Decal)。內容邊界外的像素會取樣透明黑色,使圖片外緣看起來模糊,並超出原始邊界。 模糊的狗圖片,邊緣柔和地淡出,超出原始邊界。

如要瞭解這些 API 如何在完整的 UI 模式中結合,例如淡出捲動內容的邊緣、聚焦於焦點,或使用自訂著色器遮蓋模糊效果,請參閱「常見的模糊處理用途」。