Android 图层混合模式PorterDuff.Mode

2020-03-31  本文已影响0人  刘小厨

Android 图层混合模式 PorterDuff.Mode

PorterDuff.Mode它是将所绘制的图形的像素与Canvas中对应位置的像素按照一定规则进行混合,形成新的像素值,从而更新Canvas中最终的像素颜色值.
PorterDuff.Mode共有18种
Android 中使用 图层混合模式常见的地方有三种:

  1. 组合渲染ComposeShader (详见: Android Paint总结)

  2. 画笔: Paint.setXfermode()

  3. 颜色过滤器: PorterDuffColorFilter

本文主要简单说下第二种 画笔: Paint.setXfermode()

PorterDuff.Mode

每一个图层混合模式代表一种规则,根据每种规则计算混合之后的透明通道值和颜色值
使用图层混合模式有几个需要注意的点:

图层混合模式仅作用于src源图像

意思是:以下面谷歌的demo中的第一个为例使用的模式为PorterDuff.Mode.CLEAR
,源图像src为矩形图 目标图为圆形图dst,PorterDuff.Mode.CLEAR表示清除所有颜色值和透明通道,我们从效果可以看到,目标图dst只有与源图像src相交的地方才会有影响

禁用硬件加速

原因: 在Android api 14之后,图层混合的有些api是不支持硬件加速的,系统的硬件加速是默认开启的,所以在使用图层混合模式之前,禁用掉硬件加速 ,方式如下:

//禁止硬件加速
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);

离屏绘制

原因: 在不采用离屏绘制的情况下,控件的背景会影响图层混合模式的计算结果,导致得到期望之外的效果
我们看下使用/不使用 离屏绘制的区别:


使用离屏绘制.gif 不使用离屏绘制.gif

通过使用离屏绘制(离屏缓冲),把要绘制的内容单独绘制在缓冲层,保证Xfermode的使用不会出现错误的结果

离屏绘制有两种使用方式,一般使用第一种方式就足够了:

 int saveId= canvas.saveLayer(0, 0, width, height, Canvas.ALL_SAVE_FLAG);
                canvas.translate(x, y);
                canvas.drawBitmap(mDstB, 0, 0, paint);//绘制操作
                paint.setXfermode(xfermode);//设置xfermode
                canvas.drawBitmap(mSrcB, 0, 0, paint);//绘制操作
                paint.setXfermode(null); //用完清除
                canvas.restoreToCount(saveId);//图层恢复
setLayerType(LAYER_TYPE_HARDWARE,paint);//使用GPU缓冲
setLayerType(LAYER_TYPE_SOFTWARE,paint);//使用一个Bitmap缓冲

下面我们直接看下 谷歌的 demo->Xfermodes.java
效果图如下:

Xfermodes.png

看下PorterDuff.Mode各种模式以及代表的意思:

//其中Sa全称为Source alpha表示源图的Alpha通道;Sc全称为Source color表示源图的颜色;Da全称为Destination alpha表示目标图的Alpha通道;Dc全称为Destination color表示目标图的颜色,[...,..]前半部分计算的是结果图像的Alpha通道值,“,”后半部分计算的是结果图像的颜色值。
    //效果作用于src源图像区域
    private static final Xfermode[] sModes = {
            //所绘制不会提交到画布上
            new PorterDuffXfermode(PorterDuff.Mode.CLEAR),
            //显示上层绘制的图像
            new PorterDuffXfermode(PorterDuff.Mode.SRC),
            //显示下层绘制图像
            new PorterDuffXfermode(PorterDuff.Mode.DST),
            //正常绘制显示,上下层绘制叠盖
            new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER),

            //上下层都显示,下层居上显示
            new PorterDuffXfermode(PorterDuff.Mode.DST_OVER),
            //取两层绘制交集,显示上层
            new PorterDuffXfermode(PorterDuff.Mode.SRC_IN),
            //取两层绘制交集,显示下层
            new PorterDuffXfermode(PorterDuff.Mode.DST_IN),
            //取上层绘制非交集部分,交集部分变成透明
            new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT),

            //取下层绘制非交集部分,交集部分变成透明
            new PorterDuffXfermode(PorterDuff.Mode.DST_OUT),
            //取上层交集部分与下层非交集部分
            new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP),
            //取下层交集部分与上层非交集部分
            new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP),
            //去除两图层交集部分
            new PorterDuffXfermode(PorterDuff.Mode.XOR),

            //取两图层全部区域,交集部分颜色加深
            new PorterDuffXfermode(PorterDuff.Mode.DARKEN),
            //取两图层全部区域,交集部分颜色点亮
            new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN),
            //取两图层交集部分,颜色叠加
            new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY),
            //取两图层全部区域,交集部分滤色
            new PorterDuffXfermode(PorterDuff.Mode.SCREEN),

            //取两图层全部区域,交集部分饱和度相加
            new PorterDuffXfermode(PorterDuff.Mode.ADD),
            //取两图层全部区域,交集部分叠加
            new PorterDuffXfermode(PorterDuff.Mode.OVERLAY)
    };

小案例:刮刮卡

上一篇 下一篇

猜你喜欢

热点阅读