android.graphics.Shader

        Shader我们不妨把它翻译成着色器,它是一个基本类,用来在进行绘制操作时提供颜色,它的子类通过函数paint.setShader(shader)将自身安装在paint当中,然后paint在画任何东西(除了Bitmap)的时候就会在该Shader中取颜色。我们不妨将canvas看成是画布,paint看成是画笔,画笔是要沾取颜料才能画画的,没有设置Shader的时候,画笔是在Color中沾取颜色的,每次沾取一个颜色,想换别的颜色还得重新沾。设置了Shader之后,画笔就在Shader中自动沾取颜色,每画一个点都跟Shader中对应的颜色一样。这要涉及到如何对应的问题。

      先看Shader中的成员,首先它有个内部枚举类,Shader.TileMode,该枚举有三个值,CLAMP,MIRROR,REPEAT,看下sdk中对这三个值的解释分别是,

CLAMP   重复Shader边缘的颜色,当paint要画超出了Shader范围的地方时。(这个paint是指安装了Shader的paint)

MIRROR 水平和垂直的使用Shader的镜像图片,这样使图片依然是连接的。

REPEAT  重复的使用Shader的图片。

在实际使用中我们发现其实这三个模式都是当paint要画超出了Shader范围的地方时,paint该如何取色,第一个是反复在shader的边缘取颜色,第二个是从shader的右边往左边取色或者从下边往上边取色,就是反方向开始取色。第三个是继续从shader的左边往右边或者上边往下边取色。

    Shader里边有三个函数,

public Shader()
public boolean getLocalMatrix(Matrix localM)
public void setLocalMatrix(Matrix localM)

第一个是构造函数,第二个是获取shader中的matrix,如果获取的不是标准matrix,那么就返回true,第三个是设置一个matrix给shader,如果matrix为null,那么就设置一个标准矩阵给shader。

下面我们来看shader的5个子类,

 

BitmapShader

该类的简介是使用该着色器可以使图片画起来有纹理(texture,注意这个词,很多安卓游戏引擎里边画图片就是做了Texture这么一个类),它可以设置重复模式和镜像模式。

该类剩下的内容就是一个构造函数,再也没别的什么介绍了,

public BitmapShader(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY)

bitmap是该着色器中要用到的图片,tileX表示在x方向要选择何种模式,tileY表示在y方向要选择何种模式。

看下如何应用吧

 Bitmap b1,b2; 
 BitmapShader bs1;

b1=BitmapFactory.decodeResource(this.getContext().getResources(), R.drawable.tx);

bs1=new BitmapShader(b1,Shader.TileMode.MIRROR,Shader.TileMode.MIRROR);

canvas.drawColor(Color.WHITE);

 Paint paint=new Paint();
 paint.setShader(bs1);
 canvas.drawRect(0, 0, 240, 300, paint);

选择的图片尺寸是144x192,这时候可以看到在x轴超出144的地方画的内容跟<144的地方成镜像显示,两者结合无缝,y轴也是如此,当选择Shader.TileMode.REPEAT模式的时候在x轴超出144的地方和<144的地方画的内容是一样的,中间明显有根线。选择Shader.TileMode.CLAMP时,超出144的地方就全是144那个位置的颜色了。

当然你也可以画别的尺寸的别的形状的东东,比如canvas.drawCircle(100f, 100f, 30f, paint);画出来的就是该图片在对应位置的显示,显示的是一个圆形的图片,有锯齿,不过只要设置paint.setAntiAlias(true);锯齿就没了。这样的话可以通过bitmapshader画出任何你想要的图片的部分,不像BitmapRegionDecoder只能截取矩形,比canvas的clip也要灵活很多。当然bitmapshader还有很多用法,跟ShapeDrawable连在一起用的时候也比较多.

LinearGradient

这是将颜色线性分布在一条线上的shader,有两个初始化函数

public LinearGradient(float x0, float y0, float x1, float y1, int[] colors, float[] positions,Shader.TileMode tile)
public LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1,Shader.TileMode tile)

x0,y0起始位置,x1,y1终点位置,colors需要铺洒在直线上的颜色数组,positions表示colors中的颜色各自占的比重,如果为null,则colors的颜色会均匀的洒在直线上。

tile还是表示shader模式,不过这个比起bitmapshader没那么好理解了,就是画布上的点颜色如何与shader对应,超出shader的范围又该如何重复或者镜像。

当直线是与x轴或者y轴平行的话这个也很好理解,当不平行的时候,我们试着画一个全屏矩形,可以发现颜色分布成三角形似的分布,同一个斜率的直线颜色一样。调用举例

 int colors[]=new int[]{Color.RED,Color.GREEN,Color.BLUE};
 float positions[]=new float[]{0.1f,0.2f,0.7f};
// LinearGradient lg=new LinearGradient(0,0,20,100,Color.RED,Color.GREEN,Shader.TileMode.REPEAT);
 LinearGradient lg=new LinearGradient(0,0,20,100,colors,positions,Shader.TileMode.REPEAT); 
 Paint paint=new Paint();
 paint.setShader(lg);
 paint.setAntiAlias(true);
 canvas.drawRect(0, 0, 240, 320, paint);

RadialGradient

这个是着色器以一个原点为中心,放射性的向周围铺上各种颜色,每一个以原点为中心,相同半径的圆周线颜色是一样的,初始化函数照样有两个

public RadialGradient (float x, float y, float radius, int[] colors, float[] positions, Shader.TileMode tile)
public RadialGradient (float x, float y, float radius, int color0, int color1, Shader.TileMode tile)

且看一个例子吧

 RadialGradient rg=new RadialGradient(50.f,50.f,50.f,Color.RED,Color.GREEN,Shader.TileMode.CLAMP);

 Paint paint=new Paint();
 paint.setShader(rg);

 paint.setAntiAlias(true);
 canvas.drawCircle(50.f, 50.f, 50.f, paint);

这时候我们可以看到显示的图片,并且可以看到颜色如何分布,就是感觉怪怪的,貌似这样的图形没什么用。只要改变下两个颜色的值和坐标位置,就可发现用它可以画出球形来:

    int red = (int)(100 + Math.random() * 155);
    int green = (int)(100 + Math.random() * 155);
    int blue = (int)(100 + Math.random() * 155);
    int color = 0xff000000 | red << 16 | green << 8 | blue;
    int darkColor = 0xff000000 | red/4 << 16 | green/4 << 8 | blue/4;   
 RadialGradient rg=new RadialGradient(37.5f,12.5f,50.f,color,darkColor,Shader.TileMode.CLAMP);

 Paint paint=new Paint();
 paint.setShader(rg);

 paint.setAntiAlias(true);
 canvas.drawCircle(50.f, 25.f, 50.f, paint);

这时候画出来的图形可以明显看出是个球。

SweepGradient

该shader的作用是选定一个中心点,从中心点像四周均匀的扩散颜色值。与RadialGradient的扩散不一样,它虽然也是以圆周的方式扩散,但是每条圆周线上均匀的分布着选中的那几种颜色,除了均匀分布,当然也可以以选定的比重分布

两个初始化函数

public SweepGradient (float cx, float cy, int[] colors, float[] positions)
public SweepGradient (float cx, float cy, int color0, int color1)

它的初始化只有中心点,没有半径,就是以中心点向四周无线扩散。positions还是用于设置各自颜色比重,范围[0,1],如果里边的值都一样,会得到不想得到的效果,最好设置成null,这样函数会自动排铺颜色。看应用:

 SweepGradient sg=new SweepGradient(100,100,Color.RED,Color.GREEN);

 Paint paint=new Paint();
 paint.setShader(sg);

 paint.setAntiAlias(true);
 canvas.drawCircle(100.f, 100.f, 50.f, paint);

可以看到显示效果是绿色沿着圆周慢慢的转化到红色,红绿之间一条明显的线分割开。之前说到Shader类的时候看到有两个函数,可以看出Shader有个matrix,那么这个matrix是用来干什么的呢,在SweepGradient例子中用了下,发现它就是用来改变Shader的点的坐标的,Shader中的坐标都会经过一个matrix的变换后再应用到paint中,

我设置的是translate改变,加了三句代码

 Matrix matirx=new Matrix();

 matirx.setTranslate(20, 20);
 sg.setLocalMatrix(matirx);

ComposeShader

这是一个联合Shader,将两个Shader以Xfermode或者PorterDuff.Mode的模式联合在一起组成一个着色器,看初始函数

public ComposeShader (Shader shaderA, Shader shaderB, Xfermode mode)
public ComposeShader (Shader shaderA, Shader shaderB, PorterDuff.Mode mode)

参数很明朗,一看就知,写个例子应用下吧

 SweepGradient sg=new SweepGradient(100,100,Color.RED,Color.GREEN);

 LinearGradient lg=new LinearGradient(0,0,20,100,Color.RED,Color.GREEN,Shader.TileMode.REPEAT);

ComposeShader cs=new ComposeShader(lg,sg,PorterDuff.Mode.SRC_ATOP);

 Paint paint=new Paint();
 paint.setShader(cs);

 paint.setAntiAlias(true);
 canvas.drawCircle(100.f, 100.f, 50.f, paint);

这样画出来的东东跟单独设置sg的图貌似一样啊,而且我把sg和lg的位置换了下发现画的图就跟单独用lg的图一样了,我看初始化函数里边对参数的解释是shaderA在模式里边被看成dst,shaderB被看成src,看来谁在后边就像谁啊,不过也可能是模式选择的问题。

顺带说说PorterDuff.Mode这个东东,原来在colorfilter里边用过,当时没怎么明白是怎么回事,这回算懂点了,它是有两个颜色通过该mode来进行变换,比如dst,src两种颜色,把两种颜色都拆分成 (Da,Dc),(Sa,Sc)前面表示alpha值,后边表示颜色值,都是int型,然后经过设置的变换后比如[Sa, Sa * Dc + Sc * (1 - Da)],得到新的alpha,color,经过组合后画出在画布上。  

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值