Android自定义view之paint.setShader()方法
前面两篇我们讲了canvas的一些方法,今天我们来看下paint的setShader方法。
那么shader是什么呢?听听android怎么说:“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是一个在绘制过程中返回水平跨度即水平方向颜色的基础类,就是说它是一种颜色的变化过程而不是一种具体的颜色,当paint调用了paint.setShader(shader)时候就会创建一个shader的子类设置给画笔。在设置之后除了bitmap的任何对象在用画笔绘制的时候都由shader告诉其颜色该怎么绘制。是的,我们都用shader的子类来设置给画笔,我们下面就看看shader的五种子类。
- LinearGradient(float x0, float y0, float x1, float y1,@ColorInt int color0, @ColorInt int color1,@NonNull TileMode tile):这个shader是线性的颜色渐变,来看参数(x0,y0)和(x1,y1)两个坐标,因为是水平方向的,所以说渐变颜色线开始的位置就是从(x0,y0)做一条跟x轴平行的直线,渐变颜色线结束的位置就是从(x1,y1)做一条跟x轴平行的直线,这两条直线之间的区域(当然这个区域也是在我们绘制的图形内部的)就是颜色渐变的区域,color0是渐变的起始颜色,color1是渐变的结束颜色,我们有这么一个shader对象,Shader shader = new LinearGradient(200, 0, 200, 400, Color.BLUE, Color.RED, Shader.TileMode.CLAMP)且用设置了这个shader对象的paint绘制了一个圆canvas.drawCircle(200, 200, 200, paint),咱们运行看下效果:
我们渐变的开始颜色是蓝色,渐变的结束颜色是红色,然后我们绘制的圆心是在(200,200)圆的半径是200,然后呢我们绘制的开始点是(200,0)正好是我们绘制的圆的顶点,而结束点(200, 400)则是我们绘制的圆的底部的点,所以渐变绘制一次的长度恰好是圆的直径。刚我们没说LinearGradient构造方法的最后一个参数TileMode,它是指shader的平铺模式的,啥意思呢?就是shader绘制一次的长度小于我们绘制图形的最大长度(例如圆就是直径)时候,才会展现出效果,咱们把LinearGradient的绘制终点修改为(200,200)看看效果:
这次我们看到的效果不如第一个那么线性渐变,而是到某一个地方自后全部都是一致的红色,为啥全部是红色而不是蓝色呢?这就是我们刚说的TileMode在起作用,我们设置的是Shader.TileMode.CLAMP),这个模式意思是什么呢?“replicate the edge color if the shader draws outside of its original bounds”如果shader在其范围之外绘制那么就会重复边缘处的颜色,咱们解释一下:第二次咱们绘制的起始点是 (200,0)结束点是(200,200),结束点正好是圆心,所以说shader的一次绘制区域就是圆的顶点(想象一条直线)到圆心(再想象一条直线),所以其绘制区域只是圆的一半,但是圆的另一半也得绘制呀,所以CLAMP就说了另外一般该怎么绘制,就是要重复绘制边缘处的颜色,而上面我们绘制结束点在圆心,结束颜色是红色,那么自然后面的半圆也是用红色填充的了。咱们再换TileMode的别的枚举值Shader.TileMode.REPEAT它的意思是“repeat the shader's image horizontally and vertically”就是在水平和垂直方向上重复shader的图像,我们将最后一个参数改为Shader.TileMode.REPEAT然后运行看看效果如何:
咦,这次平铺了,所以REPEAT就是这么简单,就是在我们绘制的图形内部,不断的重复shader的效果直到填充满我们绘制的图形。然后咱们看TileMode第三个值:MIRROR,它跟REPEAT的区别在于不是简单的重复,可以看到上面的REPEAT模式,两次绘制之间的衔接非常生硬,甚至有黑条的感觉。先看看MIRROR的效果如何:
这次跟上面的repeat相比衔接更加柔和一些了,因为为了有这种柔和镜像的感觉,所以shader绘制完毕一次之后,下次开始绘制是以结束的颜色绘制的,所以如上所示是蓝红红蓝而不是repeat那种一直是蓝红蓝红了。关于LinearGradient就讲这么多,主要的颜色是按照一条直线线性变化的。
- RadialGradient(float centerX, float centerY, float radius,@ColorInt int centerColor, @ColorInt int edgeColor, @NonNull TileMode tileMode):这种shader是从一个圆形向四周发散的效果变化,同样先画canvas.drawCircle(200, 200, 200, paint);这样一个圆,然后构建shader如下Shader shader = new RadialGradient(200, 200, 200, Color.BLUE, Color.RED, Shader.TileMode.MIRROR);paint.setShader(shader);参数就是需要设置圆心和半径了,这里我设置的跟绘制的圆是一样的,所以正好一个圆就是一次绘制的结束,我们来看效果:
因为我们shader设置圆形和半径与我们绘制的圆心和半径都一致,所以就执行一次绘制,那想多次执行绘制怎么办?就把每次的绘制区域设置的比我们绘制的图形区域设置的小就好了,TileMode的效果类比上面的LinearGradient就好了
- SweepGradient(float cx, float cy, @ColorInt int color0, @ColorInt int color1):它是一个围绕一个中心扫描的shader,有点像雷达扫描,咱们直接看效果:
,我们这里(cx,cy)跟圆心设置的是一致的,所以扫描是围绕着圆形进行的,同样要想看出别的TileMode效果,那么就让扫描区域小一些就好了
- BitmapShader(@NonNull Bitmap bitmap, @NonNull TileMode tileX, @NonNull TileMode tileY):上面的都是用的颜色做的填充,这里我们用bitmap来做填充我们绘制的图形,好比我们绘制了一个圆,然后让一个图片去填充它,那么岂不是可以做圆形的头像了嘛,可以往这方面考虑下的,上面的构造方法后两个参数指的是在用bitmap填充时候在x和y方向上分别按照什么模式填充了,具体效果可以自行尝试,毕竟纸上得来终觉浅
- ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB,@NonNull PorterDuff.Mode mode):这个是最难理解的,就是一种混合的shader,是针对于两个bitmapshader的,这个类的作用是“Create a new compose shader, given shaders A, B, and a combining PorterDuff mode.When the mode is applied, it will be given the result from shader A as its "dst", and the result from shader B as its "src".”大致意思是:给出shaderA,shaderB和一个两者组合的模式PorterDuff,且根据此创建一个新的组合的shader。当应用了这种模式的时候,它将会拿出shaderA作为dst目标图像并且拿shaderB作为source源图像,然后这两个图像有一些折叠或者裁剪的操作后组合在一起产生一个效果,这个shader最关键的地方在PorterDuff.Mode这种模式,说起来比较抽象,咱们直接看Android例子好了:
首先给出了src和dst了,对应构造函数里面的shaderB和shaderA了,PorterDuff.Mode主要分为两大类,第一类是Alpha compositing modes即使根据透明度合成的模式,图像如下:
接下来我用语言把每一个都描述一遍,希望大家不会觉得乱:SRC 只展示src的shader图像;SRC_OVER 就是将src覆盖在dst上面;SRC_IN 只展示src覆盖dst的部分,如果是src全部覆盖在dst上面,那么就全部展示src,如果只是遮盖一部分,那么就只展示一部分;SRC_ATOP 展示dst图像以及src覆盖在dst上面的那一部分;DST 只展示dst的shader图像;DST_OVER 现在是两个图像上下互换位置后的覆盖效果(跟SRC_OVER是反着来的);DST_IN 只展示dst覆盖src的部分,如果是dst全部覆盖在src上面,那么就全部展示src,如果只是遮盖一部分,那么就只展示一部分;DST_ATOP 展示src的图像以及dst覆盖在src上面的那部分;CLEAR 就是清除啊,什么也不展示;SRC_OUT 展示的是 src全部区域-src覆盖在dst上面的那一部分(如果src全部覆盖在dst上,那么用这个模式就展示空白了);DST_OUT 展示的是 dst全部区域-dst覆盖在src上面的那一部分(如果dst全部覆盖在src上,那么用这个模式就展示空白了);XOR 首先将两个图像都展示出来,然后将相交那部分裁切掉。这就是compositing modes部分,其实大家也发现了,src打头的和dst打头的效果的不同就是将源图像和目标图像位置互换了;第二部分是Blending modes混合模式:
这部分更难口述了,只能大家运行起来看效果了