五、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 a l p h a o u t = 0 alpha_{out} = 0 alphaout=0 C o u t = 0 C_{out} = 0 Cout=0
PorterDuff.Mode.SRC a l p h a o u t = a l p h a s r c alpha_{out} = alpha_{src} alphaout=alphasrc C o u t = C s r c C_{out} = C_{src} Cout=Csrc
PorterDuff.Mode.DST a l p h a o u t = a l p h a d s t alpha_{out} = alpha_{dst} alphaout=alphadst C o u t = C d s t C_{out} = C_{dst} Cout=Cdst
PorterDuff.Mode.SRC_OVER 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} alphaout=alphasrc+(1−alphasrc)∗alphadst 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} Cout=Csrc+(1−alphasrc)∗Cdst
PorterDuff.Mode.DST_OVER 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} alphaout=alphadst+(1−alphadst)∗alphasrc 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} Cout=Cdst+(1−alphadst)∗Csrc
PorterDuff.Mode.SRC_IN 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} alphaout=alphasrc∗alphadst C o u t = C s r c ∗ a l p h a d s t C_{out} = C_{src} * alpha_{dst} Cout=Csrc∗alphadst
PorterDuff.Mode.DST_IN 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} alphaout=alphasrc∗alphadst C o u t = C d s t ∗ a l p h a s r c C_{out} = C_{dst} * alpha_{src} Cout=Cdst∗alphasrc
PorterDuff.Mode.SRC_OUT 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} alphaout=(1−alphadst)∗alphasrc C o u t = ( 1 − a l p h a d s t ) ∗ C s r c C_{out} = (1 - alpha_{dst}) * C_{src} Cout=(1−alphadst)∗Csrc
PorterDuff.Mode.DST_OUT 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} alphaout=(1−alphasrc)∗alphadst C o u t = ( 1 − a l p h a s r c ) ∗ C d s t C_{out} = (1 - alpha_{src}) * C_{dst} Cout=(1−alphasrc)∗Cdst
PorterDuff.Mode.SRC_ATOP a l p h a o u t = a l p h a d s t alpha_{out} = alpha_{dst} alphaout=alphadst 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} Cout=alphadst∗Csrc+(1−alphasrc)∗Cdst
PorterDuff.Mode.DST_ATOP a l p h a o u t = a l p h a s r c alpha_{out} = alpha_{src} alphaout=alphasrc 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} Cout=alphasrc∗Cdst+(1−alphadst)∗Csrc
PorterDuff.Mode.XOR 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} alphaout=(1−alphadst)∗alphasrc+(1−alphasrc)∗alphadst 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} Cout=(1−alphadst)∗Csrc+(1−alphasrc)∗Cdst
PorterDuff.Mode.DARKEN 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} alphaout=alphasrc+alphadst−alphasrc∗alphadst 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}) Cout=(1−alphadst)∗Csrc+(1−alphasrc)∗Cdst+min(Csrc,Cdst)
PorterDuff.Mode.LIGHTEN 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} alphaout=alphasrc+alphadst−alphasrc∗alphadst 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}) Cout=(1−alphadst)∗Csrc+(1−alphasrc)∗Cdst+max(Csrc,Cdst)
PorterDuff.Mode.MULTIPLY 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} alphaout=alphasrc∗alphadst C o u t = C s r c ∗ C d s t C_{out} = C_{src} * C_{dst} Cout=Csrc∗Cdst
PorterDuff.Mode.SCREEN 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} alphaout=alphasrc+alphadst−alphasrc∗alphadst 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} Cout=Csrc+Cdst−Csrc∗Cdst
PorterDuff.Mode.ADD 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)) alphaout=max(0,min(alphasrc+alphadst,1)) 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) Cout=max(0,min(Csrc+Cdst,1)
PorterDuff.Mode.OVERLAY 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} alphaout=alphasrc+alphadst−alphasrc∗alphadst 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} 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在绘制的时候启用了硬件加速,尽量采用此方法来判断是否开启了硬件加速。


相关推荐
千里马学框架18 小时前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台18 小时前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone19 小时前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc19 小时前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo21 小时前
Kotlin 协程中的 Job 结构化并发与取消
android
sun00770021 小时前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼1 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone1 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen1 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone1 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui