Xfermode 效果展示及遇到的问题

338 阅读1分钟

Xfermode 效果展示

xfermode.jpg

遇到的问题

PorterDuff.Mode是两个图像共同绘制时图像颜色融合策略。

我们写代码时很容易:单独画一个圆,再单独画一个正方形,这个两个的交集只有两个图像重叠的部分。
xfermode只处理重叠的部分。

我们写代码时,我们需要创建两个同样大小的Bitmap, 一个里面绘制圆,一个里面绘制方形,然后再做融合,就会呈现出官网一样的效果。

官网地址

PorterDuff.Mode

源码如下:

class XfermodeView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    private val paint = Paint().also { it.isAntiAlias = true }
    private val textPaint = TextPaint().also {
        it.isAntiAlias = true
        it.color = Color.BLACK
        it.textSize = 30f
    }

    private val boundsList = ArrayList<RectF>()
    private val bitmapCircles = ArrayList<Bitmap>()
    private val bitmapSquares = ArrayList<Bitmap>()
    private val porterDuffs = ArrayList<PorterDuffXfermode>()
    private val length = PorterDuff.Mode.values().size
    private val texts = ArrayList<String>()

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        val size = 3
        val itemSize = width / size
        var lineHeight: Float
        var widthSize: Float
        for (index in 0 until length) {
            lineHeight = (index / size) * itemSize.toFloat()
            widthSize = (index % size) * itemSize.toFloat()
            boundsList.add(
                RectF(
                    widthSize,
                    lineHeight,
                    itemSize.toFloat() + widthSize,
                    lineHeight + itemSize.toFloat()
                )
            )
        }

        porterDuffs.add(PorterDuffXfermode(PorterDuff.Mode.ADD.also { texts.add(it.name) }))
        porterDuffs.add(PorterDuffXfermode(PorterDuff.Mode.CLEAR.also { texts.add(it.name) }))
        porterDuffs.add(PorterDuffXfermode(PorterDuff.Mode.DARKEN.also { texts.add(it.name) }))
        porterDuffs.add(PorterDuffXfermode(PorterDuff.Mode.DST.also { texts.add(it.name) }))
        porterDuffs.add(PorterDuffXfermode(PorterDuff.Mode.DST_ATOP.also { texts.add(it.name) }))
        porterDuffs.add(PorterDuffXfermode(PorterDuff.Mode.DST_IN.also { texts.add(it.name) }))

        porterDuffs.add(PorterDuffXfermode(PorterDuff.Mode.DST_OUT.also { texts.add(it.name) }))
        porterDuffs.add(PorterDuffXfermode(PorterDuff.Mode.DST_OVER.also { texts.add(it.name) }))
        porterDuffs.add(PorterDuffXfermode(PorterDuff.Mode.LIGHTEN.also { texts.add(it.name) }))
        porterDuffs.add(PorterDuffXfermode(PorterDuff.Mode.MULTIPLY.also { texts.add(it.name) }))
        porterDuffs.add(PorterDuffXfermode(PorterDuff.Mode.OVERLAY.also { texts.add(it.name) }))
        porterDuffs.add(PorterDuffXfermode(PorterDuff.Mode.SCREEN.also { texts.add(it.name) }))

        porterDuffs.add(PorterDuffXfermode(PorterDuff.Mode.SRC.also { texts.add(it.name) }))
        porterDuffs.add(PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP.also { texts.add(it.name) }))
        porterDuffs.add(PorterDuffXfermode(PorterDuff.Mode.SRC_IN.also { texts.add(it.name) }))
        porterDuffs.add(PorterDuffXfermode(PorterDuff.Mode.SRC_OUT.also { texts.add(it.name) }))
        porterDuffs.add(PorterDuffXfermode(PorterDuff.Mode.SRC_OVER.also { texts.add(it.name) }))
        porterDuffs.add(PorterDuffXfermode(PorterDuff.Mode.XOR.also { texts.add(it.name) }))


        for (index in 0 until length) {
            bitmapCircles.add(Bitmap.createBitmap(itemSize, itemSize, Bitmap.Config.ARGB_8888))
            bitmapSquares.add(Bitmap.createBitmap(itemSize, itemSize, Bitmap.Config.ARGB_8888))
        }

        for (index in 0 until length) {
            val canvas = Canvas()
            canvas.setBitmap(bitmapCircles[index])
            paint.color = Color.parseColor("#d81b60")
            canvas.drawCircle(itemSize / 3f * 2, itemSize / 3f, itemSize / 3f, paint)
            canvas.setBitmap(bitmapSquares[index])
            paint.color = Color.parseColor("#2196f3")
            canvas.drawRect(0f, itemSize / 3f, itemSize / 3f * 2f, itemSize.toFloat(), paint)
        }
    }

    override fun onDraw(canvas: Canvas) {
        for (index in 0 until length) {
            val rectF = boundsList[index]
            val layer = canvas.saveLayer(rectF, null)
            canvas.drawBitmap(bitmapCircles[index], rectF.left, rectF.top, paint)
            // 设置xfermode
            paint.xfermode = porterDuffs[index]
            canvas.drawBitmap(bitmapSquares[index], rectF.left, rectF.top, paint)
            // 记得置空
            paint.xfermode = null
            canvas.restoreToCount(layer)
            canvas.drawText(texts[index], rectF.left + 20, rectF.top + 100, textPaint)
        }
    }
}