本文是自定义View的第二篇,主要学习:Paint
本文计划根据HenCoder系列文章就行学习,所以代码风格及博文素材可能会摘自其中。
第一篇中,学习使用Paint 的常用方法设置各种属性,配合drawxxx()方法绘制各种简单View,本篇主要对Paint进行详细了解,做出更细致、绚丽的效果。
进入正题,Paint的API主要分为以下4种:
- 颜色
- 效果
- 初始化
- drawText()相关
下面开始逐个学习:
1. 颜色:
Canvas绘制时,对颜色有三层处理:
1.1 基本颜色:
像素的基本颜色,根据绘制内容的不同而有不同的控制方式:
Canvas 的颜色填充类方法 drawColor/RGB/ARGB() 的颜色,是直接写在方法的参数里,通过参数来设置的(上期讲过了);
drawBitmap() 的颜色,是直接由 Bitmap 对象来提供的(上期也讲过了);
除此之外,是图形和文字的绘制,它们的颜色就需要使用 paint 参数来额外设置了(下面要讲的)
1.1.1 直接设置颜色:
1.1.1.1 setColor(int color)
setColor() 对应的 get 方法是 getColor()
1.1.1.2 setARGB(int a, int r, int g, int b)
和 setColor(color) 一样,它的参数用的是更直接的三原色与透明度的值。实际运用中,setColor() 和 setARGB() 哪个方便和顺手用哪个吧
1.1.2 setShader(Shader shader) 设置 Shader
Shader 这个英文单词很多人没有见过,它的中文叫做「着色器」,也是用于设置绘制颜色的。「着色器」不是 Android 独有的,它是图形领域里一个通用的概念,它和直接设置颜色的区别是,着色器设置的是一个颜色方案,或者说是一套着色规则。当设置了 Shader 之后,Paint 在绘制图形和文字时就不使用 setColor/ARGB() 设置的颜色了,而是使用 Shader 的方案中的颜色。
注意:在设置了 Shader 的情况下, Paint.setColor/ARGB() 所设置的颜色就不再起作用。
在 Android 的绘制里使用 Shader ,并不直接用 Shader 这个类,而是用它的几个子类。具体来讲有 LinearGradient RadialGradient SweepGradient BitmapShader ComposeShader 这么几个:
1.1.2.1 LinearGradient 线性渐变:
构造方法:
LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1, Shader.TileMode tile) 。
参数:
x0 y0 x1 y1:渐变的两个端点的位置
color0 color1 是端点的颜色
tile:端点范围之外的着色规则,类型是 TileMode。TileMode 一共有 3 个值可选: CLAMP, MIRROR 和 REPEAT。CLAMP (夹子模式???算了这个词我不会翻)会在端点之外延续端点处的颜色;MIRROR 是镜像模式;REPEAT 是重复模式。具体的看一下例子就明白。
1.1.2.2 RadialGradient 辐射渐变
辐射渐变很好理解,就是从中心向周围辐射状的渐变
构造方法:
RadialGradient(float centerX, float centerY, float radius, int centerColor, int edgeColor, TileMode tileMode)。
参数:
centerX centerY:辐射中心的坐标
radius:辐射半径
centerColor:辐射中心的颜色
edgeColor:辐射边缘的颜色
tileMode:辐射范围之外的着色模式。
1.1.2.3 SweepGradient 扫描渐变:
构造方法:
SweepGradient(float cx, float cy, int color0, int color1)
参数:
cx cy :扫描的中心
color0:扫描的起始颜色
color1:扫描的终止颜色
1.1.2.4 BitmapShader
用 Bitmap 来着色其实是用 Bitmap 的像素来作为图形或文字的填充。大概像这样:
构造方法:
BitmapShader(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY)
参数:
bitmap:用来做模板的 Bitmap 对象
tileX:横向的 TileMode
tileY:纵向的 TileMode。
1.1.2.5 ComposeShader 混合着色器
即两个Shader混合使用
这是没有合适logo图片,以下部分用原博文中素材
注意:上面这段代码中我使用了两个 BitmapShader 来作为 ComposeShader() 的参数,而 ComposeShader() 在硬件加速下是不支持两个相同类型的 Shader 的,所以这里也需要关闭硬件加速才能看到效果。
构造方法:ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode)
参数:
shaderA, shaderB:两个相继使用的 Shader
mode: 两个 Shader 的叠加模式,即 shaderA 和 shaderB 应该怎样共同绘制。它的类型是 PorterDuff.ModePorterDuff.Mode
PorterDuff.Mode 是用来指定两个图像共同绘制时的颜色策略的。它是一个 enum,不同的 Mode 可以指定不同的策略。「颜色策略」的意思,就是说把源图像绘制到目标图像处时应该怎样确定二者结合后的颜色,而对于 ComposeShader(shaderA, shaderB, mode) 这个具体的方法,就是指应该怎样把 shaderB 绘制在 shaderA 上来得到一个结合后的 Shader。没有听说过 PorterDuff.Mode 的人,看到这里很可能依然会一头雾水:「什么怎么结合?就……两个图像一叠加,结合呗?还能怎么结合?」你还别说,还真的是有很多种策略来结合。
最符合直觉的结合策略,就是我在上面这个例子中使用的 Mode: SRC_OVER。它的算法非常直观:就像上面图中的那样,把源图像直接铺在目标图像上。不过,除了这种,其实还有一些其他的结合方式。例如如果我把上面例子中的参数 mode 改为 PorterDuff.Mode.DST_OUT,就会变成挖空效果:
而如果再把 mode 改为 PorterDuff.Mode.DST_IN,就会变成蒙版抠图效果:
具体来说,
PorterDuff.Mode
一共有 17 个,可以分为两类:
1. Alpha 合成 (Alpha Compositing)
2. 混合 (Blending)
第一类,Alpha 合成,其实就是 「PorterDuff」 这个词所指代的算法。 「PorterDuff」 并不是一个具有实际意义的词组,而是两个人的名字(准确讲是姓)。这两个人当年共同发表了一篇论文,描述了 12 种将两个图像共同绘制的操作(即算法)。而这篇论文所论述的操作,都是关于 Alpha 通道(也就是我们通俗理解的「透明度」)的计算的,后来人们就把这类计算称为Alpha 合成 ( Alpha Compositing ) 。
看下效果吧。效果直接盗 Google 的官方文档了。源图像和目标图像:
Alpha 合成:
第二类,混合,也就是 Photoshop 等制图软件里都有的那些混合模式(multiply darken lighten 之类的)。这一类操作的是颜色本身而不是 Alpha 通道,并不属于 Alpha 合成,所以和 Porter 与 Duff 这两个人也没什么关系,不过为了使用的方便,它们同样也被 Google 加进了 PorterDuff.Mode 里。
效果依然盗