hencoder 学习自定义 view(1)
canvas.drawCircle(300,300,200,paint);
效果如下:
其中前 4 个参数为 2 个端点的坐标,两个颜色为端点散发出的颜色,最后一个变量 Shader.TileMode tile 有三种模式:CLAMP、MIRROR、REPEAT,从字面意思上可以得出 CLAMP 是最正常的模式,其次是镜像最后一个是重复渐变。
RadialGradient 辐射渐变
就是从圆的中心向外颜色渐变:
Shader shader = new RadialGradient(300, 300, 200, Color.parseColor("#E91E63"),
Color.parseColor("#2196F3"), Shader.TileMode.CLAMP);
paint.setShader(shader);
canvas.drawCircle(300,300,200,paint);
前两个参数为圆心,第三个参数为半径,第一个颜色为辐射的中心颜色,第二个则为边缘颜色。效果如下:
3. SweepGradient 扫描渐变
大概是这样:
Shader shader = new SweepGradient(300, 300, 200, Color.parseColor("#E91E63"),
Color.parseColor("#2196F3"), Shader.TileMode.CLAMP);
paint.setShader(shader);
canvas.drawCircle(300, 300, 200, paint);
效果如下:
BitmapShader 就是将 Bitmap 的像素作为图形或者文字的填充
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.batman);
Shader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint.setShader(shader);
canvas.drawCircle(300, 300, 200, paint);
没错从上面的效果可以看出 使用 drawCircle+BitmapShader 和 drawBitmap 效果一样,但是这样可以绘制出圆形的 bitmap,比如说头像。
ComposeShader 混合着色器
就是把两个 Shader 混在一起用
// 第一个 Shader:头像的 Bitmap
Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.batman);
Shader shader1 = new BitmapShader(bitmap1, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
// 第二个 Shader:从上到下的线性渐变(由透明到黑色)
Bitmap bitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.batman_logo);
Shader shader2 = new BitmapShader(bitmap2, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
// ComposeShader:结合两个 Shader
Shader shade
r = new ComposeShader(shader1, shader2, PorterDuff.Mode.SRC_OVER);
paint.setShader(shader);
canvas.drawCircle(300, 300, 300, paint);
PorterDuff.Mode.SRC_OVER:使用了两个 bitmap 进行叠加绘制。
PorterDuff.Mode 是用来指定两个 bitmap 绘制时的颜色策略。它有 17 种绘制模式,而 SRC_OVER 是最正常最常用的绘制策略。
别的模式可以参考官方文档:官方文档
1.2、setColorFilter(ColorFilter colorFilter)
为颜绘制设置颜色过滤,为绘制的内容建立一个统一的过滤策略,然后 Canvas 的 drawXXX()会对每个像素都进行过滤然后绘制出来。在 paint 中使用 setColorFilter 方法,ColorFilter 并不能直接使用,而是要使用它的三个子类:LightingColorFilter
PorterDuffColorFilter
和 ColorMatrixColorFilter
。
LightingColorFilter
用来模拟简单的光照效果
LightingColorFilter 的构造方法是 LightingColorFilter(int mul, int add),参数中的 mul 和 add 都是和颜色格式相同的 int 值,其中 mul 用来和目标像素相乘,add 用来和目标像素相加。
R' = R * mul.R / 0xff + add.R
G' = G * mul.G / 0xff + add.G
B' = B * mul.B / 0xff + add.B
一个默认的 LightingColorFilter,mul 值为 0xffffff,add 值为 0x000000,那么对于一个像素,他的计算过程就是:
R' = R * 0xff / 0xff + 0x0 = R // R' = R
G' = G * 0xff / 0xff + 0x0 = G // G' = G
B' = B * 0xff / 0xff + 0x0 = B // B' = B
如果我们将红色移除,可以把 mul 值改成 0x00ffff,则 R’就计算等于 0 了。
比如说我们可以把绿色调的更加鲜艳,可以将 add 改成 0x003000,那么其 G’=G+0x30,这时候绿色就更加的鲜艳了~
ColorFilter lightingColorFilter = new LightingColorFilter(0xffffff, 0x003000);
paint.setColorFilter(lightingColorFilter);
PorterDuffColorFilter
用一个指定的颜色和一个指定的 ProterDuff.Mode 来对绘制对象进行合成。和之前的 ComposeShader 相比的区别就是之前是用 Bitmap 来进行合成,而这次就只能指定用一种颜色源。
ColorMatrixColorFilter
ColorMatrixColorFilter 使用一个 ColorMatrix 来对颜色进行处理。 ColorMatrix 这个类,内部是一个 4x5 的矩阵:
[ a, b, c, d, e,
f, g, h, i, j,
k, l, m, n, o,
p, q, r, s, t ]
通过计算,ColorMartix 可以要把绘制的像素进行转化,对于颜色【R,G,B,A】来说,转化算法是这样的:
R’ = aR + bG + cB + dA + e;
G’ = fR + gG + hB + iA + j;
B’ = kR + lG + mB + nA + o;
A’ = pR + qG + rB + sA + t;
还可以通过 setSatuation(float sat)来进行设置饱和度,具体如何就不说了。
这里有个通过 ColorMatrixColorFilter 做的开源滤镜库StyleImageView
以上就是 Paint 对颜色的第二层处理:通过 setColorFilter(colorFilter)来进行像素过滤从而达到加工颜色的效果。
Paint 最后一层处理颜色的方法就是 setXfermode,它处理的是 [当颜色遇上 View] 的问题。
1.3 setXfermode
“Xfermode"其实就是"Transfer mode”,准确的定义是当你要绘制的内容和 Canvas 的目标位置的内容应该怎样结合计算去得出最终的颜色。通俗地说,其实就是要你以绘制的内容作为源图像,以 View 中已有的内容作为目标图像,选取一个 PorterDuff.Mode 作为绘制内容的颜色处理方案。就像这样:
Xfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
...
canvas.drawBitmap(rectBitmap, 0, 0, paint); // 画方
paint.setXfermode(xfermode); // 设置 Xfermode
canvas.drawBitmap(circleBitmap, 0, 0, paint); // 画圆
paint.setXfermode(null); // 用完及时清除 Xfermode
得到的效果是这样:
另外,从上面的示例代码可以看出,创建 Xfermode 的时候其实是创建的它的子类 PorterDuffXfermode。而事实上,Xfermode 也只有这一个子类。
使用 Xfemode 时我们要注意两点:
使用离屏缓存
我们实际上在不做处理时使用上述的代码并不能直接得到那么理想的结果,而是:
这是因为在第二步画圆的时候,和正方形一起进行计算并不是这个圆,而是这个带圆的 view,而且因为 View 的底色并不是默认的透明色,所以导致这些底色也参与了计算,这个时候我们需要开启离屏缓存 (Off-screen Buffer) ,先让绘制的内容在屏幕之外绘制好,最后再贴回 view 中:
评论