如何为Vector Drawable内部透明区域填色且不填充外部矩形边界?
解决Vector Drawable内部透明区域填色的编程方案

核心思路:分层绘制+遮罩组合
要给内部透明区域(比如眼部)单独填色,同时保留原有实心部分的颜色,无需新建Vector Drawable,可通过Canvas分层绘制+遮罩控制实现,具体步骤如下:
1. 生成原Drawable的反向遮罩(仅保留内部透明区域)
先创建一个仅包含原Drawable透明区域的Bitmap遮罩,后续填充颜色时只会作用在这些区域:
fun getInverseMask(drawable: Drawable): Bitmap { val bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888) val canvas = Canvas(bitmap) // 绘制黑色背景 canvas.drawColor(Color.BLACK) // 用CLEAR模式绘制原Drawable,清除实心部分,留下透明区域的黑色填充 drawable.setBounds(0, 0, bitmap.width, bitmap.height) drawable.setColorFilter(PorterDuffColorFilter(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)) drawable.draw(canvas) // 反转颜色:原透明区(黑色)变白色,作为有效遮罩范围 val paint = Paint() paint.colorFilter = PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN) val invertedBitmap = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888) val invertCanvas = Canvas(invertedBitmap) invertCanvas.drawBitmap(bitmap, 0f, 0f, paint) bitmap.recycle() return invertedBitmap }
2. 分层绘制实现多色填充
在目标View的onDraw方法中按顺序绘制:
- 第一步:用目标颜色(比如红色)通过遮罩填充眼部区域
- 第二步:绘制带原有色调(比如绿色)的原Drawable
示例代码:
override fun onDraw(canvas: Canvas) { super.onDraw(canvas) val originalDrawable = ContextCompat.getDrawable(context, R.drawable.your_vector) ?: return // 1. 绘制红色眼部区域 val inverseMask = getInverseMask(originalDrawable) val redPaint = Paint().apply { color = Color.RED xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN) } canvas.drawBitmap(inverseMask, 0f, 0f, redPaint) // 2. 绘制原Drawable的绿色实心部分 originalDrawable.setColorFilter(PorterDuffColorFilter(Color.GREEN, PorterDuff.Mode.SRC_ATOP)) originalDrawable.setBounds(0, 0, width, height) originalDrawable.draw(canvas) inverseMask.recycle() }
3. 轻量优化:多层ColorFilter组合
如果不想创建Bitmap遮罩,可通过叠加ColorFilter实现,无需额外Bitmap:
fun getEyeTintFilter(eyeColor: Int): ColorFilter { // 第一步:将原Drawable的透明区域转为白色,实心区域转为透明 val invertMatrix = ColorMatrix().apply { setScale(-1f, -1f, -1f, 1f) postTranslate(1f, 1f, 1f, 0f) } val invertFilter = ColorMatrixColorFilter(invertMatrix) // 第二步:用目标颜色填充白色区域(原透明区) val colorFilter = PorterDuffColorFilter(eyeColor, PorterDuff.Mode.SRC_IN) // 组合滤镜 return PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP).apply { setColorFilter(invertFilter) setColorFilter(colorFilter) } }
使用时先绘制眼部颜色图层,再绘制原色调Drawable:
val eyeLayer = originalDrawable.mutate() eyeLayer.colorFilter = getEyeTintFilter(Color.RED) eyeLayer.draw(canvas) originalDrawable.colorFilter = PorterDuffColorFilter(Color.GREEN, PorterDuff.Mode.SRC_ATOP) originalDrawable.draw(canvas)
内容的提问来源于stack exchange,提问作者Satty
相关产品推荐
相关产品推荐

