关于着色器LinearGradient的使用

Posted brave-sailor

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于着色器LinearGradient的使用相关的知识,希望对你有一定的参考价值。

LinearGradient我们可以将之译为线型渐变、线型渲染等,译成什么不重要,重要的是它的显示效果是什么样子,今天我们就一起来看看。

先来看看LinearGradient的构造方法:

  1.     /** Create a shader that draws a linear gradient along a line. 
  2.         @param x0           The x-coordinate for the start of the gradient line 
  3.         @param y0           The y-coordinate for the start of the gradient line 
  4.         @param x1           The x-coordinate for the end of the gradient line 
  5.         @param y1           The y-coordinate for the end of the gradient line 
  6.         @param  colors      The colors to be distributed along the gradient line 
  7.         @param  positions   May be null. The relative positions [0..1] of 
  8.                             each corresponding color in the colors array. If this is null, 
  9.                             the the colors are distributed evenly along the gradient line. 
  10.         @param  tile        The Shader tiling mode 
  11.     */  
  12.     public LinearGradient(float x0, float y0, float x1, float y1, int colors[], float positions[],  
  13.             TileMode tile) {  
  14. .........  
  15. .....  
  16. ......  
  17.         }  


LinearGradient的构造方法共有七个参数,分别表示:

x0表示渲染起始位置的x坐标,y0表示渲染起始位置的y坐标,x1表示渲染结束位置的x坐标,y1表示渲染结束位置的y坐标,colors表示渲染的颜色,它是一个颜色数组,数组长度必须大于等于2,positions表示colors数组中几个颜色的相对位置,是一个float类型的数组,该数组的长度必须与colors数组的长度相同。如果这个参数使用null也可以,这时系统会按照梯度线来均匀分配colors数组中的颜色,最后一个参数则表示平铺方式,有三种,我们分别来看:

为了给大家演示不同平铺方式下使用着色器的不同效果,我自定义了一个View,叫做AboutShaderView,我重写了该View中的两个方法,分别是onMeasure以及onDraw,在onMeasure方法中,我把该控件的宽高固定为256dp,代码如下:

  1. @Override  
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  3.     super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  4.     setMeasuredDimension((int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 256, getResources().getDisplayMetrics()), (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 256, getResources().getDisplayMetrics()));  
  5. }  


然后在onDraw方法中通过使用着色器的不同模式,来让它显示不同的效果,最后,我在布局文件中引用自定义View:

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout  
  3.     xmlns:android="http://schemas.android.com/apk/res/android"  
  4.     xmlns:tools="http://schemas.android.com/tools"  
  5.     android:layout_width="match_parent"  
  6.     android:layout_height="match_parent"  
  7.     android:orientation="vertical"  
  8.     tools:context="lenve.customtextview.MainActivity">  
  9.     <lenve.customtextview.AboutShaderView  
  10.         android:layout_width="256dp"  
  11.         android:layout_height="256dp"/>  
  12. </LinearLayout>  

 

OK,下面我们一起来看看这几种不同模式的显示效果:

1.LinearGradient.TileMode.CLAMP

这种模式表示重复最后一种颜色直到该View结束的地方,如果我设置着色器开始的位置为(0,0),结束位置为(getMeasuredWidth(), 0)表示我的着色器要给整个View在水平方向上渲染不同的颜色,代码如下:

  1. @Override  
  2. protected void onDraw(Canvas canvas) {  
  3.     super.onDraw(canvas);  
  4.     Paint paint = new Paint();  
  5.     paint.setColor(Color.GREEN);  
  6.     LinearGradient linearGradient = new LinearGradient(0, 0, getMeasuredWidth(), 0,new int[]{Color.RED, Color.WHITE, Color.BLUE}, null, LinearGradient.TileMode.CLAMP);  
  7.     paint.setShader(linearGradient);  
  8.     canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),paint);  
  9. }  


显示效果如下:

技术分享

水平方向上依次是红白蓝,没问题,那我如果变换一下需求,我想把渲染的方向修改为从左上角到右下角,那么该怎么办?很简单,只需要修改渲染结束的位置为getMeasuredHeight()即可,代码如下:

  1. @Override  
  2. protected void onDraw(Canvas canvas) {  
  3.     super.onDraw(canvas);  
  4.     Paint paint = new Paint();  
  5.     paint.setColor(Color.GREEN);  
  6.     LinearGradient linearGradient = new LinearGradient(0, 0, getMeasuredWidth(), getMeasuredHeight(),new int[]{Color.RED, Color.WHITE, Color.BLUE}, null, LinearGradient.TileMode.CLAMP);  
  7.     paint.setShader(linearGradient);  
  8.     canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),paint);  
  9. }  


显示效果如下:

技术分享

OK,两个小Demo让大家先感受下Shader,下面我继续变换的我的需求,如果我希望我的着色器的渲染位置变为从(0,0)到(getMeasuredWidth()/2, 0),那么这时候的渲染区域是什么呢?如下图:

技术分享

OK,也就是说控件只有一半会被渲染,那么剩下的一半怎么办呢?这时候就得看我们的最后一个参数了,我们已经说过,LinearGradient.TileMode.CLAMP模式表示重复最后一种颜色直到该View结束的地方,也就是说从View宽度的1/2处直到View结束的地方都将是蓝色(因为View1/2处的颜色是蓝色),那么究竟是不是呢,我们看代码:

  1. @Override  
  2. protected void onDraw(Canvas canvas) {  
  3.     super.onDraw(canvas);  
  4.     Paint paint = new Paint();  
  5.     paint.setColor(Color.GREEN);  
  6.     LinearGradient linearGradient = new LinearGradient(0, 0, getMeasuredWidth()/2, 0,new int[]{Color.RED, Color.WHITE, Color.BLUE}, null, LinearGradient.TileMode.CLAMP);  
  7.     paint.setShader(linearGradient);  
  8.     canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),paint);  
  9. }  


再看效果图:

技术分享

和我们想的一样,这就是LinearGradient.TileMode.CLAMP模式的特点。

2.LinearGradient.TileMode.REPEAT

LinearGradient.TileMode.REPEAT表示着色器在水平或者垂直方向上对控件进行重复着色,类似于windows系统桌面背景中的“平铺”,那么接下来我们来看看着色器对这种模式的处理方式,假如我希望着色器开始渲染的位置为(0,0),结束渲染的位置为(getMeasuredWidth()/2, getMeasuredHeight()/2),但与之前不同的是这次的平铺方式变为LinearGradient.TileMode.REPEAT,我们来看看代码:

  1. @Override  
  2. protected void onDraw(Canvas canvas) {  
  3.     super.onDraw(canvas);  
  4.     Paint paint = new Paint();  
  5.     paint.setColor(Color.GREEN);  
  6.     LinearGradient linearGradient = new LinearGradient(0, 0, getMeasuredWidth()/2, getMeasuredHeight()/2,new int[]{Color.RED, Color.WHITE, Color.BLUE}, null, LinearGradient.TileMode.REPEAT);  
  7.     paint.setShader(linearGradient);  
  8.     canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),paint);  
  9. }  


效果图如下:

技术分享

OK,沿着举行对角线,着色器对View进行了重复渲染,为了大家更好的理解LinearGradient.TileMode.REPEAT模式,这次我把我的需求该一下,我希望从(0,0)处开始渲染,到(0, getMeasuredHeight()/2)处结束,这时系统会在垂直方向上重复渲染,代码如下:

  1. @Override  
  2. protected void onDraw(Canvas canvas) {  
  3.     super.onDraw(canvas);  
  4.     Paint paint = new Paint();  
  5.     paint.setColor(Color.GREEN);  
  6.     LinearGradient linearGradient = new LinearGradient(0, 0, 0, getMeasuredHeight()/2,new int[]{Color.RED, Color.WHITE, Color.BLUE}, null, LinearGradient.TileMode.REPEAT);  
  7.     paint.setShader(linearGradient);  
  8.     canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),paint);  
  9. }  


效果图如下:

技术分享

OK,没问题,如我们所预料的那样。

3.LinearGradient.TileMode.MIRROR

LinearGradient.TileMode.MIRROR模式会在水平方向或者垂直方向上以镜像的方式进行渲染,这种渲染方式的一个特征就是具有翻转的效果,比如我希望我的着色器开始渲染的位置为(0,0),结束渲染的位置为(getMeasuredWidth()/2, 0),那么效果图是什么样子呢?我们先来看看代码:

  1. @Override  
  2. protected void onDraw(Canvas canvas) {  
  3.     super.onDraw(canvas);  
  4.     Paint paint = new Paint();  
  5.     paint.setColor(Color.GREEN);  
  6.     LinearGradient linearGradient = new LinearGradient(0, 0, getMeasuredWidth()/2, 0,new int[]{Color.RED, Color.WHITE, Color.BLUE}, null, LinearGradient.TileMode.MIRROR);  
  7.     paint.setShader(linearGradient);  
  8.     canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),paint);  
  9. }  


效果图如下:

技术分享

OK,剩下的一部分依然被渲染,但是渲染的前后两部分是对称的,这就是LinearGradient.TileMode.MIRROR模式,很简单吧!

OK,以上就是LinearGradient的用法,有问题欢迎讨论。









以上是关于关于着色器LinearGradient的使用的主要内容,如果未能解决你的问题,请参考以下文章

退出时删除多个着色器?

使用着色器进行计算

为啥片段着色器比渲染纹理更快?

OpenGL:为啥我不能将单个浮点数从顶点着色器传递到片段着色器?

GPU着色器图灵完备吗

统一按钮在着色器中丢弃像素