五、Android绘制知识总结(Xfermode和硬件加速)

一、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在绘制的时候启用了硬件加速,尽量采用此方法来判断是否开启了硬件加速。


相关推荐
顾北川_野10 分钟前
Android CALL关于电话音频和紧急电话设置和获取
android·音视频
&岁月不待人&21 分钟前
Kotlin by lazy和lateinit的使用及区别
android·开发语言·kotlin
Winston Wood2 小时前
Android Parcelable和Serializable的区别与联系
android·序列化
清风徐来辽2 小时前
Android 项目模型配置管理
android
帅得不敢出门3 小时前
Gradle命令编译Android Studio工程项目并签名
android·ide·android studio·gradlew
problc3 小时前
Flutter中文字体设置指南:打造个性化的应用体验
android·javascript·flutter
帅得不敢出门14 小时前
安卓设备adb执行AT指令控制电话卡
android·adb·sim卡·at指令·电话卡
我又来搬代码了15 小时前
【Android】使用productFlavors构建多个变体
android
德育处主任17 小时前
Mac和安卓手机互传文件(ADB)
android·macos
芦半山17 小时前
Android“引用们”的底层原理
android·java