Jetpack Compose自定义Shadow在API26(Oreo)中模糊效果失效问题
Jetpack Compose自定义Shadow在API26上模糊失效的原因及解决办法
问题原因
BlurMaskFilter本身在API26是支持的,但Jetpack Compose默认启用硬件加速,而Android 8.0/8.1(API26-27)的硬件加速渲染管线对BlurMaskFilter的支持存在bug——硬件加速模式下,mask filter无法正确应用到Canvas绘制中,导致模糊效果丢失,仅显示纯色矩形。从API28开始,谷歌修复了该硬件加速兼容性问题,因此高版本能正常生效。
解决方案
方案1:给当前绘制禁用硬件加速
将绘制逻辑用withLayer包裹,指定使用软件渲染图层,即可让BlurMaskFilter在API26上正常工作:
修改后的修饰符代码:
fun Modifier.shadowCustom( color: Color = Color.Black, offsetX: Dp = 0.dp, offsetY: Dp = 0.dp, blurRadius: Dp = 0.dp, shapeRadius: Dp = 0.dp, ) = composed { val paint: Paint = remember { Paint() } val blurRadiusPx = blurRadius.px(LocalDensity.current) val maskFilter = remember { BlurMaskFilter(blurRadiusPx, BlurMaskFilter.Blur.NORMAL) } drawBehind { drawIntoCanvas { canvas -> // 启用软件渲染图层,兼容API26-27的MaskFilter canvas.withLayer( layerFlags = Canvas.LAYER_FLAG_SOFTWARE, paint = Paint() ) { val frameworkPaint = paint.asFrameworkPaint() if (blurRadius != 0.dp) { frameworkPaint.maskFilter = maskFilter } frameworkPaint.color = color.toArgb() val leftPixel = offsetX.toPx() val topPixel = offsetY.toPx() val rightPixel = size.width + leftPixel val bottomPixel = size.height + topPixel if (shapeRadius > 0.dp) { val radiusPx = shapeRadius.toPx() drawRoundRect( left = leftPixel, top = topPixel, right = rightPixel, bottom = bottomPixel, radiusX = radiusPx, radiusY = radiusPx, paint = paint, ) } else { drawRect( left = leftPixel, top = topPixel, right = rightPixel, bottom = bottomPixel, paint = paint, ) } } } } } private fun Dp.px(density: Density): Float = with(density) { toPx() }
提示:软件渲染会有轻微性能开销,但阴影这类小区域绘制基本无感知。
方案2:直接使用Compose官方shadow修饰符(更推荐)
官方shadow修饰符已做好全版本兼容,底层会根据API版本自动切换实现逻辑,无需手动处理版本差异:
Modifier.shadow( elevation = blurRadius, spotColor = color, ambientColor = color, shape = if (shapeRadius > 0.dp) RoundedCornerShape(shapeRadius) else RectangleShape, offset = Offset(offsetX.toPx(), offsetY.toPx()) )
官方实现经过充分测试,兼容性与稳定性均优于自定义实现。
效果对比
- API26(Oreo)修复前效果:

- API28+正常效果:

内容的提问来源于stack exchange,提问作者X jagan X
相关产品推荐
相关产品推荐

