先看一下官方解释:
/**
* Shader is the based class for objects that return horizontal spans of colors
* during drawing. A subclass of Shader is installed in a Paint calling
* paint.setShader(shader). After that any object (other than a bitmap) that is
* drawn with that paint will get its color(s) from the shader.
*/
大概的意思是:Shader是Object的子类,这些对象在绘制过程中返回颜色的水平跨度。通过Paint.setShader(shader)来使用Shader。调用了该方法后,用该paint绘制的任何对象(bitmap除外)都将从shader获得其颜色。
要如何理解这段话呢?我觉的一位博主的解释挺容易理解的,大概意思如下:
这幅图上的东西是什么,白底?黑字?再也别这样理解了,现在在学习shader呢,换一种理解方式。这张图片是由2张大小相同的纸构成的,第一张纸,纯黑色,第二张纸,纯白色的,不过第二张纸不是完整的,中间被扣走了部分,被扣走的部分,刚好看着有点像“演示文字”4个大字。然后将这两张纸重叠后,最终形成了如图所示的效果。
红纸(相当于黑纸)在下面,绿纸在上面(相当于白纸),但绿纸挖了一个洞(相当于白纸挖了“演示文字”几个字),在上面看就像是在绿纸上画了一个红色方形(相当于在白纸上写了“演示文字”几个黑字)。
OK,现在来讲shader了,shader其实就和两张纸的思维方式一样,可以这样强行理解shader,shader就是下面那张黑纸,画笔在白纸上画(Paint绘制过程),或者说划?划破白纸,扣出某个形状,再搭在黑纸上,就能看到那个形状了。
比如我们把上图的那4个字的底下那层黑纸给换成一张图片,按照我们的最新的理解方式,文字就会是这样的:
我们把上面那层白纸换成有点透明度的白纸,来看看全貌:
shader现在我们已经强行理解成下面那层的图片了,也就是说,当我们在作出如下行为的时候:
Paint paint = new Paint();
Shader shader = new Shader();
paint.setShader(shader);
实际上是修改了底层的图层,并且绘图模式变成了在上面那层扣形状,然后重叠,将下面那层的颜色通过被扣除的部分显示出来,赋予这个形状不一样的颜色。(我觉得这就是它为何叫着色器的原因,就是给文字、图形提供颜色)所以,当我们为画笔设置shader的时候,使用paint.setColor()这种方法就没有意义了。
一般情况下,我们不会直接使用Shader,而是使用Shader的子类。Shader有5个子类,分别是
顾名思义,该Shader的底部图层是一个Bitmap(通常是图片)。直接举个例子,自定义一个BitmapShaderView继承于View,部分代码如下:
一些初始化操作
private void init() {
mPaint = new Paint();
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.picture);
BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
//第一个参数是Bitmap,第二、第三个参数分别是x轴和y轴的TileMode(可以理解为显示模式)
//TileMode有三种,CLAMP(图片超过边界则复制边缘颜色)、REPEAT(无限重复)、MIRROR(镜像对称)
mPaint.setShader(bitmapShader);
}
重写onDraw方法,绘制文字
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setTextSize(200);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawText("演示文字", 150, 300, mPaint);
}
由起点(水平右半部分沿顺时针方向运动)开始,两种或多种颜色渲染(一种颜色没有意义,也不用这样实现),该Shader就取以起点为中心的颜色图层。直接说可能不太好理解,直接上实例代码,自定义一个SweepGradientView继承于View,部分代码如下:
给Paint设置SweepGradient
private void init() {
mPaint = new Paint();
SweepGradient sweepGradient = new SweepGradient(300, 300, Color.RED, Color.BLUE);
//官方解释:A Shader that draws a sweep gradient around a center point.
//以View的相对坐标为中心点,绘制一扫描梯度(从一种颜色开始,到另一种颜色结束)作为着色器
mPaint.setShader(sweepGradient);
}
同样,重写onDraw方法
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setStyle(Paint.Style.FILL);
//通过画这几个圆对比,发现只有第一个是真正具有完整梯度的,因为着色器的中心就是(300,300)
canvas.drawCircle(300, 300, 100, mPaint);
canvas.drawCircle(600, 300, 100, mPaint);
canvas.drawCircle(500, 500, 100, mPaint);
canvas.drawCircle(100, 500, 100, mPaint);
}
该Shader的底层图层是一种线性的、取两种或多种颜色(也可以是一种,但这没有意义)进行渲染的图形,还是直接上例子比较形象,以下是部分代码:
一些初始化操作,LinearGradient有两种构造方法,这里都给了例子
private void init() {
mPaint = new Paint();
mPaintTwo = new Paint();
LinearGradient linearGradient = new LinearGradient(50, 50, 500, 50,
Color.RED, Color.BLUE, Shader.TileMode.MIRROR);
//x0,y0为开始坐标,x1,y1为结束坐标,第五、六个参数分别是开始颜色和结束颜色,最后一个参数是显示模式。
mPaint.setShader(linearGradient);
int [] colors = {Color.RED, Color.BLUE, Color.GREEN, Color.YELLOW};
//float [] positions = {0.0f, 0.4f, 0.6f, 1.0f};
LinearGradient linearGradientTwo = new LinearGradient(50, 50, 1000, 50,
colors, null, Shader.TileMode.CLAMP);
//前四个参数同上,第五个参数是颜色集合,表示梯度中有多少个颜色(至少要有两个,不然报错)
//第六个参数是颜色分布集合(元素个数要和颜色个数对应,不然报错),为空则均匀分布,最后一个参数同样是显示模式
mPaintTwo.setShader(linearGradientTwo);
}
利用该Shader做底图,分别绘制了两个矩形
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setStyle(Paint.Style.FILL);
mPaintTwo.setStyle(Paint.Style.FILL);
canvas.drawRect(new RectF(50, 0, 950, 100), mPaint);
canvas.drawRect(new RectF(50, 150, 1000, 250), mPaintTwo);
}
和梯度渲染、线性渲染几乎一样,只是该Shader是以圆点为中心向四周渐变的效果。还是直接上例子,自定义RadialGradientView,部分代码如下:
一些初始化操作
private void init() {
mPaint = new Paint();
int [] colors = {Color.RED, Color.BLUE, Color.GREEN, Color.YELLOW};
RadialGradient radialGradient = new RadialGradient(500, 500, 400,
colors, null, Shader.TileMode.CLAMP);
//第一、二个参数是中心点的x、y坐标,第三个参数是半径,第四个参数是颜色集合(至少两种颜色)
//第五个参数是颜色分布(传入null表示均分),第六个参数是显示模式
//RadialGradient还有一个构造方法,跟上面差不多,就是只能指定两种颜色,这里就不演示了
mPaint.setShader(radialGradient);
}
绘制圆形
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(500, 500, 400, mPaint);
}
除了以上几个子类,还有最后一个子类ComposeShader,该类支持两个不同的Shader进行组合,模式只有一个,这里就不多介绍了。
最后附上demo
参考资料:
https://blog.csdn.net/IT_XF/article/details/82783177
https://www.jianshu.com/p/83af13b41bb6