LinearGradient 線性漸變渲染器
LinearGradient中文翻譯過來就是線性漸變的意思。線性漸變通俗來講就是給起點設(shè)置一個顏色值如#faf84d,終點設(shè)置一個顏色值如#CC423C,然后在一個區(qū)域內(nèi)繪圖,這個圖像的顏色將呈現(xiàn)非常美妙的效果,顏色會從起點顏色到終點顏色過渡。給一張圖,大家直觀感受一下。
我們看LinearGradient的API,發(fā)現(xiàn)它只有兩個構(gòu)造方法,非常簡單。
LinearGradient (float x0,
float y0,
float x1,
float y1,
int color0,
int color1,
Shader.TileMode tile)
//x0 和y0是顏色漸變的起點坐標。
//x1和y1是顏色漸變的終點坐標。
//color0是起點顏色值
//color0是終點顏色值。
//tile 就是TileMode類型參數(shù),這個我們上一篇已經(jīng)講過了。
LinearGradient的用法
-
創(chuàng)建LinearGradient對象,并設(shè)置它的起點坐標,終點坐標,起點顏色值,終點顏色值,然后設(shè)置TileMode
mShader = new LinearGradient(0,0,w,0,Color.parseColor("#faf84d"), Color.parseColor("#CC423C"), Shader.TileMode.CLAMP);
-
將Shader賦值給Paint對象。
mPaint.setShader(mShader);
-
繪制圖形
canvas.drawRect(0,0,w,h/2,mPaint);
LinearGradient還有一個構(gòu)造方法。
LinearGradient (float x0,
float y0,
float x1,
float y1,
int[] colors,
float[] positions,
Shader.TileMode tile)
需要注意的是,這里有一個int[] colors 和 float[] positions它們代表什么意思呢?
實際上LinearGradient除了可以指定起點顏色值和終點顏色值外,還有可以指定許多中間顏色值。就如彩虹一般。而colors[]數(shù)組存放的就是這樣的顏色值組合。大家看看代碼和圖片效果就可能直觀感受到。
漸變的是一個顏色序列(#faf84d,#003449,#808080,#cc423c)
mShader = new LinearGradient(0,0,w,0,new int[]{Color.parseColor("#faf84d"),Color.parseColor("#003449"),
Color.parseColor("#808080"),
Color.parseColor("#CC423C")},null,Shader.TileMode.CLAMP);
mPaint.setShader(mShader);
canvas.drawRect(0,0,w,h/2,mPaint);
顏色很豐富是不是?顏色從一個顏色過渡到另外一個顏色直到過渡到終點顏色。
大家有沒有注意到,我將上面代碼中的float[] positon置為null,而它代表了什么呢?它其實與colors數(shù)組對應(yīng),代表了各個顏色值在位置,positions數(shù)組中的值大小范圍從0.0到1.0,0.0代表起點位置,1.0代表終點位置。如果這個數(shù)組被置為空的話,顏色就會平均分配。 ,如果這個數(shù)組不為空呢?我們結(jié)合代碼效果來講解。
mShader = new LinearGradient(0,0,w,0,new int[]{Color.parseColor("#faf84d"),Color.parseColor("#003449"),
Color.parseColor("#808080"),
Color.parseColor("#CC423C")},new float[]{0.0f,0.6f,0.8f,1.0f},Shader.TileMode.CLAMP);
mPaint.setShader(mShader);
canvas.drawRect(0,0,w,h/2,mPaint);
代碼中colors[]并沒有改變,只是多了positon[],效果卻不一樣了。
new int[]{Color.parseColor("#faf84d"),Color.parseColor("#003449"),
Color.parseColor("#808080"),
Color.parseColor("#CC423C")}
new float[]{0.0f,0.6f,0.8f,1.0f}
// #faf84d對應(yīng)的position值是0.0 所以為起點位置。
// #003449對應(yīng)0.6 所以這個顏色位置起點到終點中間0.6比率的地方。
// #808080對應(yīng)0.8 這個顏色在0.8比率的地方
// #cc423c對應(yīng)1.0 這個顏色為終點處的顏色
需要注意的是,position[]數(shù)組中的數(shù)組最好是由小到大,這是為什么呢?它不支持0.8 然后再到0.6之類。大家看代碼。
mShader = new LinearGradient(0,0,w,0,new int[]{Color.parseColor("#faf84d"),Color.parseColor("#003449"),
Color.parseColor("#808080"),
Color.parseColor("#CC423C")},new float[]{0.6f,0.8f,0.2f,0.0f},Shader.TileMode.CLAMP);
可以看到顏色可以從0.6的位置過渡到0.8,后面的就不起作用了。
RadialGradient 環(huán)行渲染器
我喜歡稱它為徑向漸變,因為PHOTOSHOP中就對應(yīng)有徑向漸變的概念。
徑向漸變,所謂徑向就是輻射狀,由中心向四周輻射。
徑向漸變也只有兩個構(gòu)造方法,基本用法跟線性漸變差不多。
RadialGradient (float centerX,
float centerY,
float radius,
int centerColor,
int edgeColor,
Shader.TileMode tileMode)
//centerX 圓心的X坐標
//centerY 圓心的Y坐標
//radius 圓的半徑
//centerColor 中心顏色
//edgeColor 邊緣顏色
//tileMode 這個不用介紹了吧?
代碼如下:
mShader = new RadialGradient(w/2,h/2,w/2,Color.parseColor("#faf84d"),
Color.parseColor("#CC423C"), Shader.TileMode.CLAMP);
mPaint.setShader(mShader);
canvas.drawRect(0,0,w,h,mPaint);
效果圖:
RadialGradient (float centerX,
float centerY,
float radius,
int[] colors,
float[] stops,
Shader.TileMode tileMode)
同LinearGradient一樣,這里也有一個顏色數(shù)組和位置數(shù)組,意義也是一樣的,stop[]也可以為null,如果為null的話,color[]數(shù)組的顏色就會平均分配在區(qū)域之中。否則,它對應(yīng)的顏色就會按照比例填充。
mShader = new RadialGradient(w/2,h/2,w/2,new int[]{Color.parseColor("#00aa00"),Color.parseColor("#880033"),
Color.parseColor("#F8795A"),
Color.parseColor("#CC423C")},new float[]{0.0f,0.2f,0.8f,1.0f}, Shader.TileMode.CLAMP);
mPaint.setShader(mShader);
canvas.drawRect(0,0,w,h,mPaint);
效果圖:
SweepGradient 梯度漸變渲染器
梯度漸變,或者叫做掃描漸變。我覺得掃描更適合吧,它是指從x軸出發(fā),以逆時鐘為方向,以掃描360度形成的區(qū)域進行顏色的變換。
SweepGradient (float cx,
float cy,
int color0,
int color1)
//color0是起始顏色
//color1是終止顏色
代碼示例:
mShader = new SweepGradient(w/2,h/2,Color.RED,Color.BLUE);
mPaint.setShader(mShader);
canvas.drawRect(0,0,w,h,mPaint);
效果圖:
SweepGradient (float cx,
float cy,
int[] colors,
float[] positions)
大家應(yīng)該也明白這個方法中每個參數(shù)的含義。
mShader = new SweepGradient(w/2,h/2,new int[]{Color.RED,Color.CYAN,Color.YELLOW,
Color.GREEN,Color.MAGENTA,Color.BLUE},new float[]{0.0f,0.2f,0.3f,0.4f,0.8f,1.0f});
mPaint.setShader(mShader);
canvas.drawRect(0,0,w,h,mPaint);
我們把顏色豐富點,本來想弄成赤橙黃綠青藍紫,結(jié)果因為懶,就隨便弄了點,效果如下:
ComposeShader 組合渲染器
混合渲染,在這里我又開始稱Shader為渲染了,因為ComposeShader不僅僅用于顏色,它能將兩個Shader對象參考Xfermode規(guī)則進行顏色混合。
這張圖詳細的解釋了混合模式的組合效果,再看ComposeShader的兩個構(gòu)造方法。
ComposeShader (Shader shaderA, Shader shaderB, Xfermode mode)
ComposeShader (Shader shaderA, Shader shaderB, PorterDuff.Mode mode)
實戰(zhàn)1
編寫1個BitmapShader.
編寫1個RadiasGradient。
將它們進行混合產(chǎn)生新的Shader.
-
以新的Shader繪制一個圓。
public class CircleView extends View { private Paint mPaint; private Shader mShader; public CircleView(Context context) { this(context,null); } public CircleView(Context context, AttributeSet attrs) { this(context, attrs,0); } public CircleView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mPaint = new Paint(); mPaint.setAntiAlias(true); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //這里為了方便演示,將尺寸固定為400*400 setMeasuredDimension(400,400); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int w = getWidth(); int h = getHeight(); int radius = w <= h ? w/2 : h/2; Bitmap bmp = BitmapFactory.decodeResource(getResources(),R.drawable.repeat); Bitmap result = Bitmap.createScaledBitmap(bmp,w,h,false); //1. 編寫1個BitmapShader BitmapShader bitmapShader = new BitmapShader(result, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); //2. 編寫1個RadiasGradient RadialGradient radialGradient = new RadialGradient(radius,radius,radius,Color.BLACK,Color.TRANSPARENT, Shader.TileMode.CLAMP); //3. 將它們進行混合產(chǎn)生新的Shader ComposeShader composeShader = new ComposeShader(bitmapShader,radialGradient,new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); mPaint.setShader(composeShader); //4. 以新的Shader繪制一個圓。 canvas.drawCircle(w/2,h/2,radius,mPaint); } }
我們來看看混合后的效果是怎么樣的。
哇,好夢幻的狗狗。
實戰(zhàn)2 倒影功能
以前剛開始學(xué)Android的時候,項目里面要用到倒影,當(dāng)時的自己是寫不出來的,好在網(wǎng)上有現(xiàn)成的代碼可以copy?,F(xiàn)在我們可以運用ComposeShader來實現(xiàn)這么一個View。
需求分析
- 倒影與原圖比例為1:4。
- 倒影與原圖之間有5px的間隙。
- 倒影的下邊緣不能太平整了,要盡量跟真實的一致。
好了為了節(jié)省篇幅,我只粘貼onDraw()中的代碼。
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//定義各種寬高
int bmpWidth = 200;
int bmpHeight = 200;
int gap = 5;
int reflectionHeight = bmpHeight / 4;
//繪制原圖
Bitmap bmp = BitmapFactory.decodeResource(getResources(),R.drawable.repeat);
Bitmap result = Bitmap.createScaledBitmap(bmp,bmpWidth,bmpHeight,false);
canvas.drawBitmap(result,0,0,null);
canvas.save();
//向下移動準備在原圖下方繪制倒影
canvas.translate(0,bmpHeight+gap);
Matrix m = new Matrix();
m.postScale(-1f,1f);
m.postRotate(-180);
//將原圖水平翻轉(zhuǎn)
Bitmap texture = Bitmap.createBitmap(result,0,0,result.getWidth(),result.getHeight(),m,false);
//創(chuàng)建BitmapShader和LinearShader。
BitmapShader bitmapShader = new BitmapShader(texture, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
LinearGradient linearGradient = new LinearGradient(0,0,0,reflectionHeight,Color.BLACK,Color.TRANSPARENT, Shader.TileMode.CLAMP);
ComposeShader composeShader = new ComposeShader(bitmapShader,linearGradient,new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mPaint.setShader(composeShader);
//以混合模式繪制矩形區(qū)域,可以獲得倒影效果。
canvas.drawRect(0,0,bmpWidth,reflectionHeight,mPaint);
canvas.restore();
}
效果圖:
倒影出來了。