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

如何在Android中实现与Figma一致的Drop Shadow效果?

实现与Figma完全一致的多层Drop Shadow(Button/CardView适用)

核心思路

Figma的多层阴影本质是叠加多个独立阴影层,每个层包含X偏移、Y偏移、模糊半径、扩散半径、颜色(含透明度)。Android原生的CardView/Button默认阴影无法满足自定义需求,需要通过叠加自定义阴影Drawable或使用官方Material组件实现。


方案1:自定义ShadowDrawable + LayerDrawable叠加

通过自定义Drawable实现单个阴影的所有参数控制,再用LayerDrawable将多层阴影与原组件背景叠加,完全匹配Figma参数。

自定义ShadowDrawable代码

class ShadowDrawable : Drawable() {
    private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        style = Paint.Style.FILL
    }
    private val shadowBounds = RectF()

    // 对应Figma阴影参数
    var shadowX: Float = 0f
    var shadowY: Float = 0f
    var shadowBlur: Float = 0f
    var shadowSpread: Float = 0f
    var shadowColor: Int = Color.BLACK

    override fun draw(canvas: Canvas) {
        // 设置阴影参数:模糊半径、X/Y偏移、颜色
        paint.setShadowLayer(shadowBlur, shadowX, shadowY, shadowColor)
        // 用inset模拟扩散值:正数缩小区域,负数扩大区域(对应Figma的spread)
        shadowBounds.set(bounds)
        shadowBounds.inset(-shadowSpread, -shadowSpread)
        // 绘制圆角矩形(适配Button/CardView的圆角,可根据需求修改)
        canvas.drawRoundRect(shadowBounds, bounds.width() / 2f, bounds.height() / 2f, paint)
    }

    override fun setAlpha(alpha: Int) {
        paint.alpha = alpha
    }

    override fun setColorFilter(colorFilter: ColorFilter?) {
        paint.colorFilter = colorFilter
    }

    override fun getOpacity(): Int = PixelFormat.TRANSLUCENT
}

给Button添加多层阴影

fun setupMultiShadowButton(button: Button) {
    // 保留原按钮背景
    val originalBackground = button.background

    // 第一层阴影(完全对应Figma参数)
    val shadow1 = ShadowDrawable().apply {
        shadowX = 2f    // Figma X阴影值
        shadowY = 4f    // Figma Y阴影值
        shadowBlur = 8f // Figma模糊度
        shadowSpread = 2f // Figma扩散度
        shadowColor = Color.parseColor("#33000000") // Figma阴影颜色(注意ARGB顺序)
    }

    // 第二层阴影
    val shadow2 = ShadowDrawable().apply {
        shadowX = 0f
        shadowY = 2f
        shadowBlur = 12f
        shadowSpread = 0f
        shadowColor = Color.parseColor("#1A000000")
    }

    // 叠加阴影层与原背景
    val layers = arrayOf(shadow2, shadow1, originalBackground)
    val layerDrawable = LayerDrawable(layers)

    // 设置层间距,避免阴影被组件边界裁剪
    layerDrawable.setLayerInset(0, 16, 16, 16, 16)
    layerDrawable.setLayerInset(1, 8, 8, 8, 8)

    button.background = layerDrawable
    // 开启硬件加速,保证阴影模糊效果正确
    button.setLayerType(View.LAYER_TYPE_HARDWARE, null)
}

方案2:使用MaterialShapeDrawable(官方Material组件库)

如果项目已引入com.google.android.material:material库,可直接用MaterialShapeDrawable实现阴影,稳定性优于第三方库。

给CardView添加多层阴影

fun setupCardViewMultiShadow(cardView: CardView) {
    // 关闭CardView原生阴影
    cardView.cardElevation = 0f
    val context = cardView.context

    // 定义圆角(匹配Figma组件圆角)
    val shapeModel = ShapeAppearanceModel.builder()
        .setAllCornerSizes(16f)
        .build()

    // 第一层阴影
    val shadow1 = MaterialShapeDrawable(shapeModel).apply {
        setShadowColor(Color.parseColor("#33000000"))
        shadowCompatibilityMode = MaterialShapeDrawable.SHADOW_COMPAT_MODE_ALWAYS
        elevation = shadowBlur // 用elevation模拟模糊半径
        translateX = shadowX
        translateY = shadowY
    }

    // 第二层阴影
    val shadow2 = MaterialShapeDrawable(shapeModel).apply {
        setShadowColor(Color.parseColor("#1A000000"))
        shadowCompatibilityMode = MaterialShapeDrawable.SHADOW_COMPAT_MODE_ALWAYS
        elevation = 12f
        translateX = 0f
        translateY = 2f
    }

    // CardView背景层
    val cardBackground = MaterialShapeDrawable(shapeModel).apply {
        fillColor = ContextCompat.getColorStateList(context, R.color.white)
    }

    // 叠加层并设置给CardView
    val layers = arrayOf(shadow2, shadow1, cardBackground)
    val layerDrawable = LayerDrawable(layers)
    layerDrawable.setLayerInset(0, 16, 16, 16, 16)
    layerDrawable.setLayerInset(1, 8, 8, 8, 8)

    cardView.background = layerDrawable
}

关键注意事项

  1. 硬件加速:必须开启setLayerType(View.LAYER_TYPE_HARDWARE, null),否则阴影模糊效果会失真,尤其是大模糊值场景。
  2. 颜色格式:Figma的阴影颜色是RGBA,Android是ARGB,转换时要调整顺序(比如Figma的#00000033对应Android的#33000000)。
  3. 扩散值模拟:Android的setShadowLayer没有直接的spread参数,通过RectF.inset(-spread, -spread)扩大绘制区域来模拟,和Figma的spread逻辑完全一致。
  4. 边界裁剪:叠加阴影层时要设置setLayerInset给阴影留出空间,避免被组件边界裁剪。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 23:25:57