You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Android Compose中绘制带渐变边缘的透明圆形阴影遮罩?

如何在Jetpack Compose中实现带渐变边缘的聚光灯引导高亮效果?

需求:在引导流程里,需要让屏幕除指定区域外都变暗,该区域显示带渐变边缘的亮圆形,模拟聚光灯高亮效果,要求兼容Jetpack Compose。

我的尝试步骤

  • 绘制半透明深色遮罩
  • 用BlendMode.Clear绘制无渐变圆形,穿透遮罩
  • 再绘制带渐变边缘的透明圆形,边缘颜色与遮罩一致

代码实现

// 背景内容(实际场景中为其他内容)
Image(
    modifier = Modifier.matchParentSize(),
    painter = painterResource(id = R.drawable.hqdefault), 
    contentDescription = ""
)

val overlayShadeColor = Color.Black.copy(alpha = 0.8f)
val gradient = Brush.radialGradient(
    0.2f to Color.Transparent,
    0.5f to overlayShadeColor
)
val radius = 120.dp

Canvas(modifier = Modifier.fillMaxSize().graphicsLayer {
    alpha = 0.99f
}) {
    // 深色遮罩
    drawRect(overlayShadeColor)

    // 穿透遮罩的圆形
    drawCircle(
        color = Color.White,
        radius = radius.toPx(),
        blendMode = BlendMode.Clear
    )

    // 添加渐变边缘的圆形
    drawCircle(
        gradient,
        radius = radius.toPx(),
    )
}

存在的问题

圆形与背景的衔接处会出现一条极细(约1硬件像素)的线条,推测是BlendMode.Clear的渲染精度问题,想换一种更可靠的实现方案。

优化方案:直接通过径向渐变绘制遮罩

不需要分三步绘制,直接让遮罩本身就是中心透明、向外过渡到深色的径向渐变,一次性画出带渐变边缘的聚光灯效果,避免BlendMode.Clear带来的像素问题。

优化后代码

// 背景内容(实际场景中为其他内容)
Image(
    modifier = Modifier.matchParentSize(),
    painter = painterResource(id = R.drawable.hqdefault), 
    contentDescription = ""
)

val overlayShadeColor = Color.Black.copy(alpha = 0.8f)
val spotlightRadius = 120.dp
// 径向渐变:中心完全透明,到 spotlightRadius 位置开始过渡到遮罩色,超出后保持遮罩色
val spotlightBrush = Brush.radialGradient(
    0f to Color.Transparent,
    (spotlightRadius.toPx() / size.maxDimension) to Color.Transparent,
    (spotlightRadius.toPx() * 1.2f / size.maxDimension) to overlayShadeColor,
    1f to overlayShadeColor
)

Canvas(modifier = Modifier.fillMaxSize()) {
    // 直接绘制带聚光灯效果的遮罩
    drawCircle(
        brush = spotlightBrush,
        radius = size.maxDimension, // 用画布最大尺寸作为圆形半径,确保覆盖整个屏幕
        center = center // 聚光灯中心可根据需求调整,比如指定某个UI元素的位置
    )
}

方案说明

  • 此方案通过径向渐变直接定义遮罩的透明度变化,中心区域完全透明(露出背景),向外逐渐过渡到深色遮罩,自然实现渐变边缘
  • 无需使用BlendMode.Clear,避免了不同渲染层叠加带来的像素偏差问题
  • 可通过调整渐变的stop值,灵活控制渐变边缘的宽度和过渡效果
  • 如果需要定位到特定UI元素,可通过Modifier.onGloballyPositioned获取元素坐标,再修改drawCircle的center参数

内容的提问来源于stack exchange,提问作者startoftext

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 04:05:33