Android Studio 中如何为形状添加可自定义参数的投影效果
Android 匹配Adobe XD参数的自定义投影实现方案
下面分两种适配场景给出可直接复用的实现:
方案1:系统原生API实现(Android 9.0+ 适用)
该方案直接用系统自带的阴影能力,不需要自定义View,参数可直接对应XD的投影设置:
- 投影颜色:对应系统的
outlineAmbientShadowColor和outlineSpotShadowColor,两个参数设为相同即可匹配XD的纯色投影 - x/y轴偏移:对应View的
translationX/translationY属性 - 模糊度:对应View的
elevation属性,XD的模糊数值可按1:1转dp后赋值,不满意可微调
代码示例:
// 目标View为需要加投影的形状View shapeView.apply { // 先设置形状背景,示例为圆角矩形 background = GradientDrawable().apply { shape = GradientDrawable.RECTANGLE cornerRadius = 16.dpToPx() // 替换为你的圆角尺寸 setColor(Color.WHITE) // 替换为你的形状填充色 } clipToOutline = false outlineProvider = ViewOutlineProvider.BACKGROUND // 对应XD投影参数设置 elevation = 8.dpToPx() // 模糊度 translationX = 2.dpToPx() // x轴偏移 translationY = 4.dpToPx() // y轴偏移 // 设置投影颜色 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { outlineAmbientShadowColor = Color.parseColor("#33000000") // 替换为你的XD投影色 outlineSpotShadowColor = Color.parseColor("#33000000") } } // dp转px扩展方法 fun Int.dpToPx() = TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), Resources.getSystem().displayMetrics )
方案2:自定义绘制实现(全安卓版本兼容)
如果需要兼容Android 9以下版本,或者需要100%还原XD的异形投影效果,直接用自定义View绘制:
- 所有参数完全和XD一一对应,支持任意形状投影
- 只需要给View预留足够的padding避免投影被裁剪即可,预留尺寸 = 最大偏移量 + 模糊半径
自定义View代码示例:
class XDShadowShapeView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrs, defStyleAttr) { // 可外部直接修改的投影参数,完全对应XD配置 var shadowColor = Color.parseColor("#33000000") set(value) { field = value invalidate() } var shadowOffsetX = 2f.dpToPx() set(value) { field = value invalidate() } var shadowOffsetY = 4f.dpToPx() set(value) { field = value invalidate() } var shadowBlur = 8f.dpToPx() set(value) { field = value blurFilter = BlurMaskFilter(value, BlurMaskFilter.Blur.NORMAL) invalidate() } var shapeCornerRadius = 16f.dpToPx() set(value) { field = value invalidate() } var shapeFillColor = Color.WHITE set(value) { field = value invalidate() } private val shadowPaint = Paint(Paint.ANTI_ALIAS_FLAG) private val shapePaint = Paint(Paint.ANTI_ALIAS_FLAG) private var blurFilter: BlurMaskFilter? = null init { // BlurMaskFilter需要关闭硬件加速 setLayerType(LAYER_TYPE_SOFTWARE, null) } override fun onDraw(canvas: Canvas) { super.onDraw(canvas) val left = paddingLeft.toFloat() val top = paddingTop.toFloat() val right = width - paddingRight.toFloat() val bottom = height - paddingBottom.toFloat() // 先绘制底层投影 shadowPaint.apply { color = shadowColor maskFilter = blurFilter } canvas.drawRoundRect( left + shadowOffsetX, top + shadowOffsetY, right + shadowOffsetX, bottom + shadowOffsetY, shapeCornerRadius, shapeCornerRadius, shadowPaint ) // 再绘制上层形状 shapePaint.color = shapeFillColor canvas.drawRoundRect(left, top, right, bottom, shapeCornerRadius, shapeCornerRadius, shapePaint) } private fun Float.dpToPx() = TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, this, Resources.getSystem().displayMetrics ) }
注意事项
- 自定义绘制方案如果需要实现异形投影,只要把
drawRoundRect替换为drawPath方法绘制对应的路径即可,投影会完全跟随形状轮廓 - 如果需要实现带透明度的投影,直接给
shadowColor设置对应alpha值即可,和XD的颜色透明度设置完全匹配
内容的提问来源于stack exchange,提问作者Barrow
相关产品推荐
相关产品推荐

