Android 图层混合模式 PorterDuff.Mode
PorterDuff.Mode
它是将所绘制的图形的像素与Canvas
中对应位置的像素按照一定规则进行混合,形成新的像素值,从而更新Canvas
中最终的像素颜色值.
PorterDuff.Mode
共有18种
Android 中使用 图层混合模式常见的地方有三种:
-
组合渲染ComposeShader (详见: Android Paint总结)
-
画笔: Paint.setXfermode()
-
颜色过滤器: PorterDuffColorFilter
本文主要简单说下第二种 画笔: Paint.setXfermode()
每一个图层混合模式代表一种规则,根据每种规则计算混合之后的透明通道值和颜色值
使用图层混合模式有几个需要注意的点:
图层混合模式仅作用于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的使用不会出现错误的结果
离屏绘制有两种使用方式,一般使用第一种方式就足够了:
-
Canvas.saveLayer()
可以做短时的离屏绘制,在绘制之前保存 ,绘制之后结束,使用方式如下:
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);//图层恢复
-
View.setLayerType()
直接把整个View都绘制在离屏缓冲中,使用如下:
setLayerType(LAYER_TYPE_HARDWARE,paint);//使用GPU缓冲
setLayerType(LAYER_TYPE_SOFTWARE,paint);//使用一个Bitmap缓冲
下面我们直接看下 谷歌的 demo->Xfermodes.java
效果图如下:
看下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)
};
小案例:刮刮卡
网友评论