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


相关推荐
浩浩乎@12 分钟前
【openGLES】安卓端EGL的使用
android
Kotlin上海用户组2 小时前
Koin vs. Hilt——最流行的 Android DI 框架全方位对比
android·架构·kotlin
zzq19962 小时前
Android framework 开发者模式下,如何修改动画过度模式
android
木叶丸2 小时前
Flutter 生命周期完全指南
android·flutter·ios
阿幸软件杂货间2 小时前
阿幸课堂随机点名
android·开发语言·javascript
没有了遇见2 小时前
Android 渐变色整理之功能实现<二>文字,背景,边框,进度条等
android
没有了遇见4 小时前
Android RecycleView 条目进入和滑出屏幕的渐变阴影效果
android
站在巨人肩膀上的码农4 小时前
去掉长按遥控器power键后提示关机、飞行模式的弹窗
android·安卓·rk·关机弹窗·power键·长按·飞行模式弹窗
呼啦啦--隔壁老王4 小时前
屏幕旋转流程
android
人生何处不修行5 小时前
实战:Android 15 (API 35) 适配 & 构建踩坑全记录
android