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

如何为Vector Drawable内部透明区域填色且不填充外部矩形边界?

解决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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 21:13:23