跳转到内容

模糊效果

miuix-blur 是一个独立的 Compose Multiplatform 模糊效果库。它通过 Modifier 扩展提供背景模糊、颜色混合和纹理效果。支持 Android、Desktop (JVM)、iOS、macOS 和 Web (WasmJs/Js) 平台。

注意

在 Android 上,模糊效果需要 API 31 (Android 12) 或更高版本。通过 RuntimeShader 实现的自定义混合模式需要 API 33 (Android 13) 或更高版本。在不支持的 API 级别上,模糊 Modifier 将作为空操作。

配置

在项目中添加 miuix-blur 依赖:

kotlin
kotlin {
    sourceSets {
        commonMain.dependencies {
            implementation("top.yukonga.miuix.kmp:miuix-blur:<version>")
        }
    }
}

Android 项目:

kotlin
dependencies {
    implementation("top.yukonga.miuix.kmp:miuix-blur-android:<version>")
}

平台支持

平台RenderEffect(模糊)RuntimeShader(自定义混合模式)
AndroidAPI 31+API 33+
Desktop (JVM)支持支持
iOS / macOS支持支持
WasmJs / Js支持支持

可在运行时检查平台能力:

kotlin
import top.yukonga.miuix.kmp.blur.isRenderEffectSupported
import top.yukonga.miuix.kmp.blur.isRuntimeShaderSupported

val canBlur = isRenderEffectSupported()
val canUseCustomBlendModes = isRuntimeShaderSupported()

基本用法

应用背景模糊分为三步:

  1. 创建 LayerBackdrop 以捕获背景内容
  2. 在内容容器上应用 Modifier.layerBackdrop()
  3. 在模糊表面上应用 Modifier.textureBlur()
kotlin
import top.yukonga.miuix.kmp.blur.BlurColors
import top.yukonga.miuix.kmp.blur.BlurDefaults
import top.yukonga.miuix.kmp.blur.layerBackdrop
import top.yukonga.miuix.kmp.blur.rememberLayerBackdrop
import top.yukonga.miuix.kmp.blur.textureBlur

// 第 1 步:创建 LayerBackdrop
val backdrop = rememberLayerBackdrop()

// 第 2 步:捕获背景内容
Box(
    modifier = Modifier
        .fillMaxSize()
        .layerBackdrop(backdrop) // 捕获此 Box 的内容
) {
    // 背景内容(如图片、渐变或页面内容)
    Image(
        painter = painterResource(Res.drawable.background),
        contentDescription = null,
        modifier = Modifier.fillMaxSize(),
        contentScale = ContentScale.Crop
    )
}

背景色

layerBackdrop 仅捕获其所在 composable 绘制的内容,不包含父级 composable 的背景(例如 Scaffold 的 Surface)。如果捕获的内容存在透明区域(如无背景的文字),模糊时颜色会扩散到透明像素中,产生明显的色块。

为避免此问题,请在 onDraw lambda 中绘制不透明背景:

kotlin
val backgroundColor = MaterialTheme.colorScheme.surface
val backdrop = rememberLayerBackdrop {
    drawRect(backgroundColor) // 确保捕获到不透明背景
    drawContent()
}
kotlin

// 第 3 步:在叠加层上应用模糊
Box(
    modifier = Modifier
        .size(200.dp)
        .textureBlur(
            backdrop = backdrop,
            shape = RoundedCornerShape(16.dp)
        )
) {
    Text(
        text = "模糊卡片",
        modifier = Modifier.padding(16.dp)
    )
}

颜色配置

使用 BlurColors 在模糊效果之上应用颜色调整和混合图层:

kotlin
import top.yukonga.miuix.kmp.blur.BlendColorEntry
import top.yukonga.miuix.kmp.blur.BlurBlendMode
import top.yukonga.miuix.kmp.blur.BlurColors

val colors = BlurColors(
    blendColors = listOf(
        BlendColorEntry(
            color = Color.White.copy(alpha = 0.3f),
            mode = BlurBlendMode.SrcOver
        )
    ),
    brightness = 0.05f,  // 范围:[-1, 1],0 = 无变化
    contrast = 1.1f,     // 倍数,1 = 无变化
    saturation = 1.2f    // 倍数,1 = 无变化
)

Box(
    modifier = Modifier
        .textureBlur(
            backdrop = backdrop,
            shape = RoundedCornerShape(16.dp),
            colors = colors
        )
) {
    // 内容
}

也可以使用可组合辅助函数 BlurDefaults.blurColors(),它会自动 remember 配置:

kotlin
val colors = BlurDefaults.blurColors(
    blendColors = listOf(
        BlendColorEntry(Color.White.copy(alpha = 0.2f), BlurBlendMode.Screen)
    ),
    brightness = 0f,
    contrast = 1f,
    saturation = 1.2f
)

混合模式

BlurBlendMode 提供了 40 多种混合模式,用于模糊背景上的颜色混合。

标准模式

标准 SkBlendMode 值(0-28),使用与 Skia 兼容的预乘 Alpha 公式:

模式说明
SrcOver普通 Alpha 合成(默认)
Screen提亮混合
Multiply变暗混合
Overlay增强对比度混合
SoftLight柔和对比度调整
ColorDodge通过降低对比度提亮
ColorBurn通过增加对比度变暗
Darken保留较暗像素
Lighten保留较亮像素
Difference绝对差值
Exclusion类似 Difference 但对比度较低
Hue应用源色相
Saturation应用源饱和度
Color应用源色相和饱和度
Luminosity应用源亮度

自定义模式

自定义模式(100+),实现了 Lab 色彩空间运算、线性光混合等(需要 isRuntimeShaderSupported()):

模式说明
LinearLight线性光混合
LinearLightWithGreyscale带灰度调制的线性光
LinearLightLabLab 色彩空间中的线性光
LabLightenWithGreyscale带灰度调制的 Lab 提亮
LabDarkenWithGreyscale带灰度调制的 Lab 变暗
LabLab 颜色映射
MiColorDodge增强版颜色减淡
MiColorBurn增强版颜色加深
PlusDarker带 Alpha 合成的加暗
PlusLighter带 Alpha 合成的加亮
AlphaBlend带子级调制的 Alpha 混合
MiSaturation饱和度调整
MiBrightness亮度调整
MiLuminance明度曲线调整

示例:多层混合

kotlin
val colors = BlurColors(
    blendColors = listOf(
        BlendColorEntry(Color(0x40FFFFFF), BlurBlendMode.Screen),
        BlendColorEntry(Color(0x20000000), BlurBlendMode.Overlay)
    ),
    saturation = 1.5f
)

进阶用法

独立 X/Y 模糊半径

可对水平和垂直方向应用不同的模糊强度:

kotlin
Box(
    modifier = Modifier
        .textureBlur(
            backdrop = backdrop,
            shape = RoundedCornerShape(16.dp),
            blurRadiusX = 100f,
            blurRadiusY = 20f
        )
) {
    // 具有方向性模糊的内容
}

前景模糊(内容遮罩)

使用 contentBlendMode 创建前景模糊效果,内容的 Alpha 通道将作为模糊区域的遮罩:

kotlin
import androidx.compose.ui.graphics.BlendMode as ComposeBlendMode

Text(
    text = "磨砂文字",
    style = MiuixTheme.textStyles.title1,
    modifier = Modifier
        .textureBlur(
            backdrop = backdrop,
            shape = RectangleShape,
            blurRadius = 150f,
            contentBlendMode = ComposeBlendMode.DstIn // 内容 Alpha 遮罩模糊
        )
)

噪声抖动

noiseCoefficient 参数控制应用于模糊结果的抗条纹噪声。默认值为 0.0045f,设为 0f 可禁用:

kotlin
Box(
    modifier = Modifier
        .textureBlur(
            backdrop = backdrop,
            shape = RoundedCornerShape(16.dp),
            noiseCoefficient = 0f // 禁用噪声抖动
        )
)

低级 API:drawBackdrop

如需完全控制效果管线,可使用 Modifier.drawBackdrop() 配合 BackdropEffectScope

kotlin
import top.yukonga.miuix.kmp.blur.drawBackdrop

Box(
    modifier = Modifier
        .drawBackdrop(
            backdrop = backdrop,
            shape = { RoundedCornerShape(16.dp) },
            effects = {
                // 应用高斯模糊
                blur(radius = 60f)
                // 调整颜色
                colorControls(
                    brightness = 0.05f,
                    contrast = 1.1f,
                    saturation = 1.3f
                )
            }
        )
) {
    // 内容
}

BackdropEffectScope 扩展函数

扩展函数说明
blur(radius, edgeTreatment)应用高斯模糊
colorFilter(colorFilter)应用 ColorFilter
colorControls(brightness, contrast, saturation)调整亮度、对比度和饱和度
effect(effect)链接任意 RenderEffect
runtimeShaderEffect(key, shaderString, uniformShaderName, block)应用自定义 AGSL/SkSL 运行时着色器

像素空间 uniform 需按 downscaleFactor 缩放

runtimeShaderEffect 链接在 blur(或其他抬高 downscaleFactor 的效果)之后,backdrop layer 以 1 / downscaleFactor 的分辨率录制,shader 接收的 coord 也是该降采样后 layer 的像素坐标。任何描述像素空间距离的 uniform —— 例如 size、padding/offset、圆角半径、折射带宽等 —— 都必须在 block 内部除以 downscaleFactor,否则形状几何会落在 layer 范围之外,所有采样都会拿到透明黑色。

BackdropEffectScope 属性

属性类型说明
sizeSize当前渲染尺寸
layoutDirectionLayoutDirection当前布局方向
shapeShape当前裁剪形状
paddingFloat模糊溢出的额外内边距
renderEffectRenderEffect?累积的效果链
downscaleFactorInt降采样系数(1、2、4、8、16)
noiseCoefficientFloat全分辨率噪声抖动系数

属性

textureBlur / textureEffect 参数

参数名类型说明默认值是否必须
backdropBackdrop提供模糊背景内容的 Backdrop-
shapeShape模糊区域裁剪的形状-
blurRadiusFloat模糊半径(dp),库内部自动转换为像素。限制在 [0, 150] 范围内20f
blurRadiusXFloat水平模糊半径(dp,独立半径重载)-是*
blurRadiusYFloat垂直模糊半径(dp,独立半径重载)-是*
noiseCoefficientFloat抗条纹噪声抖动系数,0 表示禁用0.0045f
colorsBlurColors模糊后应用的颜色调整和混合图层BlurColors()
highlightHighlight?可选的边缘高光,绘制在内容之上。null 时跳过null
contentBlendModeBlendMode?内容在模糊上方合成的混合模式null
enabledBoolean是否启用模糊,为 false 时跳过效果并正常绘制内容true

* 仅在独立半径重载中必须。

BlurColors 属性

属性名类型说明默认值
blendColorsList<BlendColorEntry>在模糊背景上按顺序混合的颜色列表emptyList()
brightnessFloat亮度调整,范围 [-1, 1]0f
contrastFloat对比度倍数1f
saturationFloat饱和度倍数1f

BlurDefaults

常量类型说明
BlurRadiusFloat默认模糊半径(dp)20f
NoiseCoefficientFloat默认噪声抖动系数0.0045f
MaxBlurRadiusFloat最大允许模糊半径(dp)150f
方法返回类型说明
blurColors()BlurColors创建被 remember 的 BlurColors 实例

边缘高光

Highlight 沿圆角形状绘制一条带两路定向光的玻璃质感边缘。它通过 Modifier.textureBlur / Modifier.textureEffecthighlight 参数(恒定场景)或 Modifier.drawBackdrophighlight 参数(响应式场景,与 BackdropEffectScope 共享)绘制。配合模糊背景可营造"模糊背景上的发光边缘"效果。

配合 textureBlur(恒定)

kotlin
import androidx.compose.foundation.shape.RoundedCornerShape
import top.yukonga.miuix.kmp.blur.highlight.Highlight

Box(
    modifier = Modifier
        .size(200.dp, 100.dp)
        .textureBlur(
            backdrop = backdrop,
            shape = RoundedCornerShape(24.dp),
            highlight = Highlight.GlassStrokeMiddleLight,
        ),
)

配合 drawBackdrop(响应式)

highlight lambda 与 effects 共用同一个 BackdropEffectScope,其返回值可随状态变化(如按压进度),并自动复用当前的 size / shape

kotlin
import top.yukonga.miuix.kmp.blur.drawBackdrop
import top.yukonga.miuix.kmp.blur.blur
import top.yukonga.miuix.kmp.blur.highlight.Highlight

Box(
    modifier = Modifier
        .size(200.dp, 100.dp)
        .drawBackdrop(
            backdrop = backdrop,
            shape = { RoundedCornerShape(24.dp) },
            effects = { blur(20.dp.toPx()) },
            highlight = { Highlight.GlassStrokeMiddleLight.copy(alpha = pressProgress) },
        ),
)

null(或 width = 0.dpHighlight)即可禁用。

注意

边缘高光需要 isRuntimeShaderSupported() 支持。在不支持的平台或 API 级别上,将静默跳过绘制。

内置预设

提供六个预设,按卡片尺寸和主题选用:

预设innerBlurRadius视觉特征
Highlight.GlassStrokeBigLight3.5 dphalo 最厚最柔 — 亮模式大卡片
Highlight.GlassStrokeMiddleLight2.8 dp标准亮模式卡片(默认)
Highlight.GlassStrokeSmallLight2.6 dp紧凑、更锐利的亮模式卡片
Highlight.GlassStrokeBigDark1.7 dphalo 最薄 — 暗模式大卡片
Highlight.GlassStrokeMiddleDark2.0 dp标准暗模式卡片
Highlight.GlassStrokeSmallDark2.3 dp紧凑、最锐利的暗模式卡片

Highlight.Default 等价于 GlassStrokeMiddleLight

自定义 BloomStroke

可基于 token 覆盖单个字段,或从零构建 BloomStroke

kotlin
import top.yukonga.miuix.kmp.blur.highlight.BloomStroke
import top.yukonga.miuix.kmp.blur.highlight.LightPosition
import top.yukonga.miuix.kmp.blur.highlight.LightSource

val custom = Highlight(
    width = 1.dp,
    alpha = 0.8f,
    style = BloomStroke(
        color = Color.White.copy(alpha = 0.05f),
        innerBlurRadius = 3.dp,
        primaryLight = LightSource(
            position = LightPosition(0.5f, 0.4f, -0.5f),
            intensity = 0.4f,
        ),
        secondaryLight = LightSource(
            position = LightPosition(0.5f, 0.85f, -0.5f),
            intensity = 0.3f,
        ),
    ),
)

LightPosition 使用归一化 UV 坐标,参考原点为 (0.5, 0.7, 0)。Shader 将 (x − 0.5, y − 0.7, z) 归一化后作为 3D 方向向量。负 z 把光放在表面平面之后(从内向外照亮边缘)— 所有内置预设均使用 z < 0

两路光在 shader 中被限制到相反的半球:primaryLight 照亮圆角矩形上半部,secondaryLight 照亮下半部。y < 0.7 让光偏上;y > 0.7 让光偏下。

传感器驱动的视差

rememberTiltLight 通过设备旋转传感器实时偏移基准位置。Android 上会产生跟随设备倾斜的视差边缘;Desktop / iOS / macOS / Web 上 tilt 始终为零,光斑保持静止。

kotlin
import top.yukonga.miuix.kmp.blur.highlight.rememberTiltLight

val baseStyle = Highlight.GlassStrokeMiddleLight.style as BloomStroke

val tiltPrimary = rememberTiltLight(
    basePosition = baseStyle.primaryLight.position,
    intensity = baseStyle.primaryLight.intensity,
    sensitivity = 0.15f,
)
val tiltSecondary = rememberTiltLight(
    basePosition = baseStyle.secondaryLight.position,
    intensity = baseStyle.secondaryLight.intensity,
    sensitivity = 0.12f,
)

val highlight = Highlight.GlassStrokeMiddleLight.copy(
    style = baseStyle.copy(
        primaryLight = tiltPrimary,
        secondaryLight = tiltSecondary,
    ),
)

sensitivity 控制每弧度倾斜对应的 UV 偏移量 — 0.1f 表示在 1 rad 倾斜下光位置移动 10%。提高数值会放大视差幅度。

边缘高光属性

Highlight

属性类型说明默认值
widthDpstyle.color 绘制的描边带宽度0.8.dp
alphaFloat整体不透明度倍数,范围 [0, 1]1f
styleHighlightStyle着色模型(通常是 BloomStrokeHighlightStyle.Default

BloomStroke

属性类型说明默认值
colorColor描边带的基础颜色;alpha 驱动描边亮度White.copy(alpha = 0.05f)
blendModeBlendMode高光叠加层的合成模式BlendMode.Plus
innerBlurRadiusDp光晕从圆角向内延伸的深度 — 决定 halo 的厚度与柔度2.8.dp
primaryLightLightSource上半球定向光LightPosition(0.5f, 0.5f, -0.5f),intensity 0.4
secondaryLightLightSource下半球定向光LightPosition(0.5f, 0.8f, -0.5f),intensity 0.25

LightSource

属性类型说明默认值
positionLightPosition光的 UV 位置-
colorColor光颜色(颜色 alpha 折入贡献缩放)White
intensityFloat亮度缩放,≥ 01f

LightPosition

属性类型说明
xFloat归一化 UV x(参考原点:0.5)
yFloat归一化 UV y(参考原点:0.7)
zFloat有符号深度;负值把光放在表面之后

rememberTiltLight 参数

参数类型说明默认值
basePositionLightPosition零倾斜时的位置-
colorColor光颜色White
intensityFloat亮度缩放1f
sensitivityFloat每弧度倾斜对应的 UV 偏移量0.1f

变更日志

基于 Apache-2.0 许可发布