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
相关产品推荐
相关产品推荐

