前言
Paint作为自定义View中常用的类,对颜色的绘制可以分为三层
- paint颜色设置
- paint.setAlpha(0x20);
- paint.setColor(Color.parseColor("#1b8fe6"));
- paint.setARGB(0xff, 0xff, 0xff, 0x00);
- paint.setShader(new XXShader());着色器的优先级要高于前面颜色的设置
- 滤镜的设置
- paint.setColorFilter(new XXFilter());
- paint.setXfermode(Xfermode xfermode);Xfermode 指的是你要绘制的内容和 Canvas 的目标位置的内容应该怎样结合计算出最终的颜色。但通俗地说,其实就是要你以绘制的内容作为源图像,以 View 中已有的内容作为目标图像,选取一个 PorterDuff.Mode 作为绘制内容的颜色处理方案。
TileMode
在讲解Shader的子类之前,我们先来看看TileMode这个枚举
public enum TileMode {
CLAMP (0),
REPEAT (1),
MIRROR (2);
}
- CLAMP表示剩余部分保持最终的颜色
- REPEAT表示剩余部分重新开始渐变
- MIRRO表示剩余部分和渐变部分成镜像对称
Shader的分类
Shader着色器分为如下5类
- 渐变系列
- LinearGradient 线性渐变
- SweepGradient 角度渐变
- RadialGradient 辐射渐变
- BitmapShader
- ComposeShader
LinearGradient
线性渐变,我反手就是一段代码
protected void onDraw(Canvas canvas) {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStrokeWidth(50);
paint.setShader(new LinearGradient(50, 50, 500, 50, Color.RED, Color.YELLOW,
Shader.TileMode.CLAMP));
canvas.drawLine(50, 50, 700, 50, paint);
}
表示从(x1,y1)到(x2,y2),从startColor渐变到endColor,TileMode就是前面说的渐变模式,这里为默认的CLAMP,所以从x轴的500往后都是保持YELLOW,效果图如下所示
SweepGradient
角度渐变,我反手又是一段代码。默认是从3点钟方向(0度)位置开始顺时针渐变360度
protected void onDraw(Canvas canvas) {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStrokeWidth(50);
paint.setShader(new SweepGradient(200, 200, Color.RED, Color.YELLOW));
canvas.drawCircle(200, 200, 100, paint);
}
表示从(x,y)点为圆心,从startColor渐变到endColor。效果图如下所示
RadialGradient
辐射渐变,是一种扩散的渐变效果,我反手再来一段代码
protected void onDraw(Canvas canvas) {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStrokeWidth(50);
paint.setShader(new RadialGradient(200, 200, 50, Color.RED, Color.YELLOW,
Shader.TileMode.MIRROR));
canvas.drawCircle(200, 200, 100, paint);
}
表示以(x,y)为圆心,以radius为辐射半径,从startColor渐变到endColor,渐变模式是MIRROR。效果图如下所示
BitmapShader
我反手再来一段代码
protected void onDraw(Canvas canvas) {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStrokeWidth(50);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher_round);
paint.setShader(new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT));
canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), paint);
}
效果图如下所示
ComposeShader
这里我们使用两个BitmapShader,最后再甩一段代码
protected void onDraw(Canvas canvas) {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStrokeWidth(50);
Bitmap b1 = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher_round);
Shader s1 = new BitmapShader(b1, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
Bitmap b2 = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher_foreground);
Shader s2 = new BitmapShader(b2, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
paint.setShader(new ComposeShader(s1, s2, PorterDuff.Mode.DST_IN));
canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), paint);
}
兴高采烈的看了下运行结果,发现手机上是空白的。注意,ComposeShader在硬件加速的情况下是不支持两个相同的Shader,所以我们得关闭硬件加速。
setLayerType(LAYER_TYPE_SOFTWARE, null);
如果不明白PorterDuff.Mode的,可以看看之前写的这一篇文章PorterDuff.Mode;DST_IN表示绘制目标图像的重叠部分,效果图如下,图片选取的不好。