一、Xfermode
Xfermode表示图层的混合模式,用于描述两个图层之间进行融合时,像素点进行计算的规则。
在API16之前,Xfermode有3个子类:AvoidXfermode、PixelXorXfermode、PorterDuffXfermode。但在API16以后,前两个已经过时,甚至从源码里移除,所以我们只需学习PorterDuffXfermode
即可。
1.1、PorterDuffXfermode
PorterDuffXfermode
最早是在1984年由Porter和Duff两人发表的论文《Compositing Digital Images》中出现,所以该混合模式也根据作者来命名。
PorterDuffXfermode
构造函数需要指定一个PorterDuff.Mode
,而PorterDuff.Mode在以下地方都会涉及:
1、ComposeShader
2、Paint.setXfermode()
3、PorterDuffColorFilter
它提供18种模式可选项:
PorterDuff.Mode | 公式 |
---|---|
PorterDuff.Mode.CLEAR | <math xmlns="http://www.w3.org/1998/Math/MathML"> a l p h a o u t = 0 alpha_{out} = 0 </math>alphaout=0 <math xmlns="http://www.w3.org/1998/Math/MathML"> C o u t = 0 C_{out} = 0 </math>Cout=0 |
PorterDuff.Mode.SRC | <math xmlns="http://www.w3.org/1998/Math/MathML"> a l p h a o u t = a l p h a s r c alpha_{out} = alpha_{src} </math>alphaout=alphasrc <math xmlns="http://www.w3.org/1998/Math/MathML"> C o u t = C s r c C_{out} = C_{src} </math>Cout=Csrc |
PorterDuff.Mode.DST | <math xmlns="http://www.w3.org/1998/Math/MathML"> a l p h a o u t = a l p h a d s t alpha_{out} = alpha_{dst} </math>alphaout=alphadst <math xmlns="http://www.w3.org/1998/Math/MathML"> C o u t = C d s t C_{out} = C_{dst} </math>Cout=Cdst |
PorterDuff.Mode.SRC_OVER | <math xmlns="http://www.w3.org/1998/Math/MathML"> a l p h a o u t = a l p h a s r c + ( 1 − a l p h a s r c ) ∗ a l p h a d s t alpha_{out} = alpha_{src} + (1 - alpha_{src}) * alpha_{dst} </math>alphaout=alphasrc+(1−alphasrc)∗alphadst <math xmlns="http://www.w3.org/1998/Math/MathML"> C o u t = C s r c + ( 1 − a l p h a s r c ) ∗ C d s t C_{out} = C_{src} + (1 - alpha_{src}) * C_{dst} </math>Cout=Csrc+(1−alphasrc)∗Cdst |
PorterDuff.Mode.DST_OVER | <math xmlns="http://www.w3.org/1998/Math/MathML"> a l p h a o u t = a l p h a d s t + ( 1 − a l p h a d s t ) ∗ a l p h a s r c alpha_{out} = alpha_{dst} + (1 - alpha_{dst}) * alpha_{src} </math>alphaout=alphadst+(1−alphadst)∗alphasrc <math xmlns="http://www.w3.org/1998/Math/MathML"> C o u t = C d s t + ( 1 − a l p h a d s t ) ∗ C s r c C_{out} = C_{dst} + (1 - alpha_{dst}) * C_{src} </math>Cout=Cdst+(1−alphadst)∗Csrc |
PorterDuff.Mode.SRC_IN | <math xmlns="http://www.w3.org/1998/Math/MathML"> a l p h a o u t = a l p h a s r c ∗ a l p h a d s t alpha_{out} = alpha_{src} * alpha_{dst} </math>alphaout=alphasrc∗alphadst <math xmlns="http://www.w3.org/1998/Math/MathML"> C o u t = C s r c ∗ a l p h a d s t C_{out} = C_{src} * alpha_{dst} </math>Cout=Csrc∗alphadst |
PorterDuff.Mode.DST_IN | <math xmlns="http://www.w3.org/1998/Math/MathML"> a l p h a o u t = a l p h a s r c ∗ a l p h a d s t alpha_{out} = alpha_{src} * alpha_{dst} </math>alphaout=alphasrc∗alphadst <math xmlns="http://www.w3.org/1998/Math/MathML"> C o u t = C d s t ∗ a l p h a s r c C_{out} = C_{dst} * alpha_{src} </math>Cout=Cdst∗alphasrc |
PorterDuff.Mode.SRC_OUT | <math xmlns="http://www.w3.org/1998/Math/MathML"> a l p h a o u t = ( 1 − a l p h a d s t ) ∗ a l p h a s r c alpha_{out} = (1 - alpha_{dst}) * alpha_{src} </math>alphaout=(1−alphadst)∗alphasrc <math xmlns="http://www.w3.org/1998/Math/MathML"> C o u t = ( 1 − a l p h a d s t ) ∗ C s r c C_{out} = (1 - alpha_{dst}) * C_{src} </math>Cout=(1−alphadst)∗Csrc |
PorterDuff.Mode.DST_OUT | <math xmlns="http://www.w3.org/1998/Math/MathML"> a l p h a o u t = ( 1 − a l p h a s r c ) ∗ a l p h a d s t alpha_{out} = (1 - alpha_{src}) * alpha_{dst} </math>alphaout=(1−alphasrc)∗alphadst <math xmlns="http://www.w3.org/1998/Math/MathML"> C o u t = ( 1 − a l p h a s r c ) ∗ C d s t C_{out} = (1 - alpha_{src}) * C_{dst} </math>Cout=(1−alphasrc)∗Cdst |
PorterDuff.Mode.SRC_ATOP | <math xmlns="http://www.w3.org/1998/Math/MathML"> a l p h a o u t = a l p h a d s t alpha_{out} = alpha_{dst} </math>alphaout=alphadst <math xmlns="http://www.w3.org/1998/Math/MathML"> C o u t = a l p h a d s t ∗ C s r c + ( 1 − a l p h a s r c ) ∗ C d s t C_{out} = alpha_{dst} * C_{src} + (1 - alpha_{src}) * C_{dst} </math>Cout=alphadst∗Csrc+(1−alphasrc)∗Cdst |
PorterDuff.Mode.DST_ATOP | <math xmlns="http://www.w3.org/1998/Math/MathML"> a l p h a o u t = a l p h a s r c alpha_{out} = alpha_{src} </math>alphaout=alphasrc <math xmlns="http://www.w3.org/1998/Math/MathML"> C o u t = a l p h a s r c ∗ C d s t + ( 1 − a l p h a d s t ) ∗ C s r c C_{out} = alpha_{src} * C_{dst} + (1 - alpha_{dst}) * C_{src} </math>Cout=alphasrc∗Cdst+(1−alphadst)∗Csrc |
PorterDuff.Mode.XOR | <math xmlns="http://www.w3.org/1998/Math/MathML"> a l p h a o u t = ( 1 − a l p h a d s t ) ∗ a l p h a s r c + ( 1 − a l p h a s r c ) ∗ a l p h a d s t alpha_{out} = (1 - alpha_{dst}) * alpha_{src} + (1 - alpha_{src}) * alpha_{dst} </math>alphaout=(1−alphadst)∗alphasrc+(1−alphasrc)∗alphadst <math xmlns="http://www.w3.org/1998/Math/MathML"> C o u t = ( 1 − a l p h a d s t ) ∗ C s r c + ( 1 − a l p h a s r c ) ∗ C d s t C_{out} = (1 - alpha_{dst}) * C_{src} + (1 - alpha_{src}) * C_{dst} </math>Cout=(1−alphadst)∗Csrc+(1−alphasrc)∗Cdst |
PorterDuff.Mode.DARKEN | <math xmlns="http://www.w3.org/1998/Math/MathML"> a l p h a o u t = a l p h a s r c + a l p h a d s t − a l p h a s r c ∗ a l p h a d s t alpha_{out} = alpha_{src} + alpha_{dst} - alpha_{src} * alpha_{dst} </math>alphaout=alphasrc+alphadst−alphasrc∗alphadst <math xmlns="http://www.w3.org/1998/Math/MathML"> C o u t = ( 1 − a l p h a d s t ) ∗ C s r c + ( 1 − a l p h a s r c ) ∗ C d s t + m i n ( C s r c , C d s t ) C_{out} = (1 - alpha_{dst}) * C_{src} + (1 - alpha_{src}) * C_{dst} + min(C_{src}, C_{dst}) </math>Cout=(1−alphadst)∗Csrc+(1−alphasrc)∗Cdst+min(Csrc,Cdst) |
PorterDuff.Mode.LIGHTEN | <math xmlns="http://www.w3.org/1998/Math/MathML"> a l p h a o u t = a l p h a s r c + a l p h a d s t − a l p h a s r c ∗ a l p h a d s t alpha_{out} = alpha_{src} + alpha_{dst} - alpha_{src} * alpha_{dst} </math>alphaout=alphasrc+alphadst−alphasrc∗alphadst <math xmlns="http://www.w3.org/1998/Math/MathML"> C o u t = ( 1 − a l p h a d s t ) ∗ C s r c + ( 1 − a l p h a s r c ) ∗ C d s t + m a x ( C s r c , C d s t ) C_{out} = (1 - alpha_{dst}) * C_{src} + (1 - alpha_{src}) * C_{dst} + max(C_{src}, C_{dst}) </math>Cout=(1−alphadst)∗Csrc+(1−alphasrc)∗Cdst+max(Csrc,Cdst) |
PorterDuff.Mode.MULTIPLY | <math xmlns="http://www.w3.org/1998/Math/MathML"> a l p h a o u t = a l p h a s r c ∗ a l p h a d s t alpha_{out} = alpha_{src} * alpha_{dst} </math>alphaout=alphasrc∗alphadst <math xmlns="http://www.w3.org/1998/Math/MathML"> C o u t = C s r c ∗ C d s t C_{out} = C_{src} * C_{dst} </math>Cout=Csrc∗Cdst |
PorterDuff.Mode.SCREEN | <math xmlns="http://www.w3.org/1998/Math/MathML"> a l p h a o u t = a l p h a s r c + a l p h a d s t − a l p h a s r c ∗ a l p h a d s t alpha_{out} = alpha_{src} + alpha_{dst} - alpha_{src} * alpha_{dst} </math>alphaout=alphasrc+alphadst−alphasrc∗alphadst <math xmlns="http://www.w3.org/1998/Math/MathML"> C o u t = C s r c + C d s t − C s r c ∗ C d s t C_{out} = C_{src} + C_{dst} - C_{src} * C_{dst} </math>Cout=Csrc+Cdst−Csrc∗Cdst |
PorterDuff.Mode.ADD | <math xmlns="http://www.w3.org/1998/Math/MathML"> a l p h a o u t = m a x ( 0 , m i n ( a l p h a s r c + a l p h a d s t , 1 ) ) alpha_{out} = max(0, min(alpha_{src} + alpha_{dst}, 1)) </math>alphaout=max(0,min(alphasrc+alphadst,1)) <math xmlns="http://www.w3.org/1998/Math/MathML"> C o u t = m a x ( 0 , m i n ( C s r c + C d s t , 1 ) C_{out} = max(0, min(C_{src} + C_{dst}, 1) </math>Cout=max(0,min(Csrc+Cdst,1) |
PorterDuff.Mode.OVERLAY | <math xmlns="http://www.w3.org/1998/Math/MathML"> a l p h a o u t = a l p h a s r c + a l p h a d s t − a l p h a s r c ∗ a l p h a d s t alpha_{out} = alpha_{src} + alpha_{dst} - alpha_{src} * alpha_{dst} </math>alphaout=alphasrc+alphadst−alphasrc∗alphadst <math xmlns="http://www.w3.org/1998/Math/MathML"> C o u t = { 2 ∗ C s r c ∗ C d s t 2 ∗ C d s t < α d s t a l p h a s r c ∗ α d s t − 2 ( α d s t − C s r c ) ( α s r c − C d s t ) o t h e r w i s e C_{out} = \begin{cases} 2 * C_{src} * C_{dst} & 2 * C_{dst} \lt \alpha_{dst} \\ alpha_{src} * \alpha_{dst} - 2 (\alpha_{dst} - C_{src}) (\alpha_{src} - C_{dst}) & otherwise \end{cases} </math>Cout={2∗Csrc∗Cdstalphasrc∗αdst−2(αdst−Csrc)(αsrc−Cdst)2∗Cdst<αdstotherwise |
各种模式下的效果如下图所示:
-
1、如果原图和目标图大小一致(图中,两者大小均占满整个小方格区域):
-
2、如果原图和目标图大小不一致(图中,两者大小为可见大小):
这里可以发现,两种效果是不一样的,谷歌官方给的是第一种,但是,通常情况应该是第二种,具体原因可参考该文章。
比如我们画一个矩形,应该按第二种效果来考虑,因为源图和目标图大小不一致;如果画相同大小的Bitmap,则按第一种做。
在实际应用中,我们可以从以下三个方面来决定使用哪种模式:
1、目标图像和源图像混合,需不需要生成颜色的叠加特效。如果需要,则从颜色叠加相关模式中选择,有Mode.ADD(饱和度相加)、Mode.DARKEN(变暗)、Mode.LIGHTEN(变亮)、Mode.MULTIPLY (正片叠底)、Mode.OVERLAY(叠加)、Mode.SCREEN(滤色)。
2、当不需要特效,而需要根据某张图片的透明像素来裁剪时,就需要使用SRC相关模式或DST相关模式了。而SRC相关模式与DST相关模式是相通的,唯一不同的是决定当前哪个图像是目标图像和源图像。
3、当需要清空图像时,使用Mode.CLEAR模式。
1.1、实例:
二、硬件加速
2.1、View的绘制模型
1、没有硬件加速:
invalidate the view hierarchy ------> draw the view hierarchy
2、有硬件加速:
invalidate the view hierarchy ------> record and update the display list ------> draw the display list
2.2、开启硬件加速后的异常
1、绘制不正确:可能使用了不支持硬件加速的操作, 需要关闭硬件加速或者绕过该操作
2、抛出异常:可能使用了不支持硬件加速的操作, 需要关闭硬件加速或者绕过该操作
2.3、禁用GPU硬件加速
在Android系统中,有4个不同级别的打开或者关闭硬件加速操作:
1、Application级别:
<application android:hardwareAccelerated="false">
默认为true,用于控制这个app是否开启硬件加速。
2、Activity级别:
<activity android:hardwareAccelerated="false">
3、Window级别:(只支持开启操作)
getWindow().setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
4、View级别:(只支持关闭操作)
view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
LAYER_TYPE_HARDWARE
,使用硬件加速(GPU)进行绘制
LAYER_TYPE_SOFTWARE
,使用CPU进行绘制
或者布局文件中,指定以下属性:
android:layerType="software"
2.4、检测是否开启硬件加速
1、view.isHardwareAccelerated()
如果返回true,表示view挂在一个开启了硬件加速的Window之下,也就意味着,它在绘制时,并不一定开启了硬件加速。
2、canvas.isHardwareAccelerated()
如果返回true,因为着canvas在绘制的时候启用了硬件加速,尽量采用此方法来判断是否开启了硬件加速。