Compose 中的模糊处理

模糊效果可柔化视觉细节、营造摄影景深,并将焦点吸引到前景界面元素。在 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 如何在完整的界面模式中组合使用,例如淡化滚动内容的边缘、突出显示焦点或使用自定义着色器遮盖模糊效果,请参阅常见的模糊处理用例。