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

API 29以下设备中Compose setShadowLayer替代实现方案咨询

适配API 29以下的Compose高级阴影实现

由于setShadowLayer在硬件加速渲染模式下仅支持API 29及以上版本,我们可以通过版本分支处理,为API 29以下设备提供Canvas渐变模拟阴影的方案,同时保留高版本的原生实现。

修改后的完整代码

import android.os.Build
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Paint
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.toPx

fun Modifier.advancedShadow(
    color: Color = Color.Black,
    alpha: Float = 1f,
    cornersRadius: Dp = 0.dp,
    shadowBlurRadius: Dp = 0.dp,
    offsetY: Dp = 0.dp,
    offsetX: Dp = 0.dp
) = drawBehind {
    val shadowColor = color.copy(alpha = alpha)
    val blurRadiusPx = shadowBlurRadius.toPx()
    val offsetXPx = offsetX.toPx()
    val offsetYPx = offsetY.toPx()
    val cornersRadiusPx = cornersRadius.toPx()

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        // API 29+ 保留原生setShadowLayer实现
        val transparentColor = color.copy(alpha = 0f).toArgb()
        drawIntoCanvas {
            val paint = Paint()
            val frameworkPaint = paint.asFrameworkPaint()
            frameworkPaint.color = transparentColor
            frameworkPaint.setShadowLayer(
                blurRadiusPx,
                offsetXPx,
                offsetYPx,
                shadowColor.toArgb()
            )
            it.drawRoundRect(
                0f,
                0f,
                size.width,
                size.height,
                cornersRadiusPx,
                cornersRadiusPx,
                paint
            )
        }
    } else {
        // API 29以下 用径向渐变+遮罩模拟阴影
        val shadowAreaSize = Size(
            width = size.width + blurRadiusPx * 2,
            height = size.height + blurRadiusPx * 2
        )
        val shadowOffset = Offset(
            x = offsetXPx - blurRadiusPx,
            y = offsetYPx - blurRadiusPx
        )

        // 绘制径向渐变阴影
        drawCircle(
            color = shadowColor,
            radius = maxOf(shadowAreaSize.width, shadowAreaSize.height) / 2,
            center = Offset(shadowAreaSize.width / 2 + shadowOffset.x, shadowAreaSize.height / 2 + shadowOffset.y),
            alpha = alpha * 0.25f // 调整透明度适配视觉效果
        )

        // 用圆角矩形遮罩裁剪出符合控件形状的阴影
        drawRoundRect(
            color = Color.Transparent,
            topLeft = shadowOffset,
            size = shadowAreaSize,
            cornerRadius = CornerRadius(cornersRadiusPx + blurRadiusPx),
            blendMode = BlendMode.DstIn
        )
    }
}

关键说明

  • 版本分支:通过Build.VERSION.SDK_INT判断系统版本,高版本保留原生高效实现,低版本用Canvas模拟
  • 模拟原理:用径向渐变生成模糊效果,再通过圆角矩形遮罩裁剪出与控件匹配的阴影形状,最后通过偏移参数控制阴影位置
  • 视觉调整:可以修改模拟部分的alpha值、渐变范围,让阴影效果更接近原生
  • 性能注意:Canvas模拟的阴影性能略低于原生,但在大多数场景下足够流畅,避免在高频重绘的控件中过度使用复杂参数

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 01:36:01