本文为专项介绍Paint类
Paint 类
1.颜色
canvas 绘制内容,有三层颜色处理
1.1基本颜色
Canvas的颜色填充方法:drawColor/drawRGB/drawARGB() ,直接将颜色值作为参数传入。
drawBitmap() 填充bitmap的颜色,是有Bitmap对象来提供。
图形和文字的颜色由Paint的参数来设置。
注:Paint设置颜色的两种方式:
1.Paint.setColor/ARGB()来设置颜色。
2.通过设置Shader(调色板)来设置颜色方案。
1.1.1 直接设置颜色
--paint.setColor(Color.RED);
--paint.setColor(Color.parseColor("#003000"));
--paint.setARGB(int a,int b,int g,int b)
1.1.2 设置Shader
介绍 Shader : Shader 为着色器,用于设置绘制有颜色。他是图形领域通用的概念。他与直接设置颜色不同的是,着色器设置的是一个颜色方案。
在Android中,Shader的子类:LinearGradient RadialGradient SweepGradient BitmapShader ComposeShader
1.1.2.1 LinearGradient 线性渐变
先设置两个点,然后有以这两个点为断电,使用两种颜色的渐变来绘制
例:
Shadershader=newLinearGradient(100,100,500,500,Color.parseColor("#E91E63"),Color.parseColor("#2196F3"),Shader.TileMode.CLAMP);
canvas.drawRect(100,100,500,500,paint);
注:在设置Shader后,Paint.setColor/ARGB() 所设置的颜色就不会再起作用。
构造方法:
LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1, Shader.TileMode tile)
参数:
--x0,y0 x1,y1:渐变的两个端点的位置。
--color0,color1:端点的颜色。
--title 端点范围之外的着色规则。
TileMode 是个枚举类,共三个值:
CLAMP:用彩色边缘来填充多余空间
MIRROR:重复使用镜像模式来的图像来填充多余空间
REPEAT:重复图像来填充多余空间
1.1.2.2 RadialGradient 辐射渐变
从中心来向四周辐射
例:
Shadersharder=newRadialGradient(300,300,200,Color.parseColor("#E91E63"),Color.parseColor("#2196F3"),Shader.TileMode.CLAMP);
canvas.drawCircle(300,300,200,paint);
构造方法:
RadialGradient(float centerX, float centerY, float radius, int centerColor, int edgeColor, TileMode tileMode)。
参数:
centerX centerY:辐射中心的坐标
radius:辐射半径
centerColor:辐射中心的颜色
edgeColor:辐射边缘的颜色
tileMode:辐射范围之外的着色模式。
1.1.2.3 SweepGradient 扫描渐变
类似与雷达扫描
例:
Shadershader=newSweepGradient(300,300,Color.parseColor("#E91E63"),Color.parseColor("#2196F3"));
canvas.drawCircle(300,300,200,paint);
构造方法
SweepGradient(float cx, float cy, int color0, int color1)
参数:
cx cy :扫描的中心
color0:扫描的起始颜色
color1:扫描的终止颜色
1.1.2.4 BitmapShader
用Bitmap 的像素来作为图形或者文字的填充。
例:
Bitmapbitmap=BitmapFactory.decodeResource(getResources(),R.drawable.what_the_fuck);
Shadershader=newBitmapShader(bitmap,Shader.TileMode.CLAMP,Shader.TileMode.CLAMP);
canvas.drawCircle(200,200,200,paint);
实际上他与 Canvas.drawBitmap()效果类似。
绘制圆形Bitmap,就可以使用drawCircle() + BitmapShader()
构造方法:
BitmapShader(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY)
参数:
bitmap:用来做模板的 Bitmap 对象
tileX:横向的 TileMode
tileY:纵向的 TileMode。
注:这里的title,需要设置纵向跟横向的。
CLAMP:
MIRROR:
REPAT:
1.1.2.5 ComposeShader 混合着色器
简而言之:将两个Shader 一起用。
例:
setLayerType(LAYER_TYPE_SOFTWARE,null);
Bitmapbitmap=BitmapFactory.decodeResource(getResources(),R.drawable.what_the_fuck);
Shadershader=newBitmapShader(bitmap,Shader.TileMode.CLAMP,Shader.TileMode.CLAMP);
Bitmapbitmap1=BitmapFactory.decodeResource(getResources(),R.drawable.batman_logo);
Shadershader1=newBitmapShader(bitmap1,Shader.TileMode.CLAMP,Shader.TileMode.CLAMP);
Shadershader2=newComposeShader(shader,shader1,PorterDuff.Mode.DST_IN);
paint.setShader(shader2);
注:这里需要禁用硬件加速。ComposeShader() 在硬件加速条件下不支持两个同类型的Shader。
构造方法:
ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode)
参数:
shaderA, shaderB:两个相继使用的 Shader
mode: 两个 Shader 的叠加模式,即 shaderA 和 shaderB 应该怎样共同绘制。它的类型是PorterDuff.Mode
PorterDuff.Mode
ProterDuff.Mode是一个枚举类,他是用来指定两个图像共有绘制时的颜色策略。他通过不同mode类型类指定不同的策略。(简单的说,就是两个图形,指定他们以什么样的方式合并成一个图形)
PorterDuff.Mode 共有17个类型,分为两类
1.Alpha 合成 12种类
2.混合(Blending)
Alpha 合成:其实就是 「PorterDuff」 这个词所指代的算法。 「PorterDuff」 并不是一个具有实际意义的词组,而是两个人的名字(准确讲是姓)。这两个人当年共同发表了一篇论文,描述了 12 种将两个图像共同绘制的操作(即算法)。而这篇论文所论述的操作,都是关于 Alpha 通道(也就是我们通俗理解的「透明度」)的计算的,后来人们就把这类计算称为Alpha 合成 ( Alpha Compositing ) 。
Google 官方效果
源图像和目标图像
Alpha合成
混合:也就是 Photoshop 等制图软件里都有的那些混合模式(multiply darken lighten 之类的)。这一类操作的是颜色本身而不是 Alpha 通道,并不属于 Alpha 合成,所以和 Porter 与 Duff 这两个人也没什么关系,不过为了使用的方便,它们同样也被 Google 加进了 PorterDuff.Mode 里。
由上图可看出:Alpha合成类的效果直观,混合类的效果比较抽象。当我们掌握了Alpha类的合成,记住混合类的名字,当我们再看到复杂UI的设计图的时候,自己马上就能知道能不能做,怎么做了。
1.2 setColorFilter(ColorFilter colorFilter)
ColorFilter类:为绘制设置颜色过滤(就是为绘制的内容设置一个统一的过滤策略,然后Canvas.drawXXX()方法对每个像素都进行过滤后再绘制出来)。
在 Paint 里设置 ColorFilter ,使用的是 Paint.setColorFilter(ColorFilter filter) 方法。 ColorFilter 并不直接使用,而是使用它的子类。它共有三个子类:LightingColorFilter PorterDuffColorFilter 和 ColorMatrixColorFilter。
1.2.1 LightingColorFilter(模拟简单的光照效果)
LightingColorFilter 的构造方法是 LightingColorFilter(int mul, int add) ,参数里的 mul 和 add 都是和颜色值格式相同的 int 值,其中 mul 用来和目标像素相乘,add 用来和目标像素相加:
一个「保持原样」的「基本 LightingColorFilter 」,mul 为 0xffffff,add 为 0x000000(也就是0),那么对于一个像素,它的计算过程就是:
基于这个「基本 LightingColorFilter 」,你就可以修改一下做出其他的 filter。比如,如果你想去掉原像素中的红色,可以把它的 mul 改为 0x00ffff (红色部分为 0 ) ,那么它的计算过程就是:
ColorFilter lightingColorFilter = new LightingColorFilter(0x00ffff, 0x000000);
paint.setColorFilter(lightingColorFilter);
1.2.2 PorterDuffColorFilter
PorterDuffColorFilter 他的作用是使用一个指定的颜色和一种指定的PorterDuff.Mode来与绘制对象进行合成。
构造方法:
PorterDuffColorFilter(int color, PorterDuff.Mode mode)
参数:
color 参数是指定的颜色
mode 参数是指定的 Mode。同样也是 PorterDuff.Mode ,不过和 ComposeShader 不同的是,PorterDuffColorFilter 作为一个 ColorFilter,只能指定一种颜色作为源,而不是一个 Bitmap。
1.2.3 ColorMatrixColorFilter
ColorMatrixColorFilter 他是使用一个ColorMatrix来对颜色进行处理。ColorMatrix类,他的内部是一个4*5的矩阵。
通过计算,ColorMatrix 可以把要绘制的像素进行转换。对于颜色【R,G,B,A】,转换算法:
关于ColorMatrix,推荐StyleImageView
1.3 setXfermode(Xfermode xfermode)
Xfermode 指的是你要绘制的内容和 Canvas 的目标位置的内容应该怎样结合计算出最终的颜色。
其实就是将你要绘制的内容作为源图像,以View中已有的内容作为目标图像,选取一个PorterDuffer.Mode绘制内容的颜色处理方案。
例:
又是 PorterDuff.Mode 。 PorterDuff.Mode 在 Paint 一共有三处 API ,它们的工作原理都一样,只是用途不同:
注:Xfermode 只有一个子类(PorterDuffXfermode)。
Xfermode 注意事项
1.使用离屏缓冲(Off-screen Buffer)
上面的代码如果直接执行不会绘制出图中效果。程序在执行的时候,也不会是上面的流程。
按照逻辑我们会认为,在第二步画圆的时候,跟它共同计算的是第一步绘制的方形。但实际上,却是整个 View 的显示区域都在画圆的时候参与计算,并且 View 自身的底色并不是默认的透明色,而且是遵循一种迷之逻辑,导致不仅绘制的是整个圆的范围,而且在范围之外都变成了黑色。就像这样:
要想使用setXfermode()正常绘制,必须使用离屏缓冲(Off-screen Buffer)把绘制的内容绘制在额外的图层上,再将绘制好的内容贴回到View中。
离屏缓冲的方式:
1.Canvas。saveLayer() saveLayer() 可以做短时的离屏缓冲
2.View.setLayerType() 是直接把整个 View 都绘制在离屏缓冲中
setLayerType(LAYER_TYPE_HARDWARE) 是使用 GPU 来缓冲, setLayerType(LAYER_TYPE_SOFTWARE) 是直接直接用一个 Bitmap 来缓冲。
注:
如果没有特殊需求,可以选用第一种方法 Canvas.saveLayer() 来设置离屏缓冲,以此来获得更高的性能。
2.控制好透明区域
如图所示,由于透明区域过小而覆盖不到的地方,将不会受到 Xfermode 的影响。
所以,我们在使用Xfermode绘制内容时候,除了注意离屏缓冲,还需要注意控制透明区域的大小,要让他足够覆盖到要和他结合绘制的内容。