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


相关推荐
还鮟2 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡4 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi004 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体
zhangphil5 小时前
Android理解onTrimMemory中ComponentCallbacks2的内存警戒水位线值
android
你过来啊你6 小时前
Android View的绘制原理详解
android
移动开发者1号8 小时前
使用 Android App Bundle 极致压缩应用体积
android·kotlin
移动开发者1号8 小时前
构建高可用线上性能监控体系:从原理到实战
android·kotlin
ii_best13 小时前
按键精灵支持安卓14、15系统,兼容64位环境开发辅助工具
android
美狐美颜sdk14 小时前
跨平台直播美颜SDK集成实录:Android/iOS如何适配贴纸功能
android·人工智能·ios·架构·音视频·美颜sdk·第三方美颜sdk
恋猫de小郭18 小时前
Meta 宣布加入 Kotlin 基金会,将为 Kotlin 和 Android 生态提供全新支持
android·开发语言·ios·kotlin