LinearGradient 線性漸變渲染器 LinearGradient中文翻譯過來就是線性漸變的意思。線性漸變通俗來講就是給起點設置一個顏色值如#faf84d,終點設置一個顏色值如#CC423C,然後在一個區域內繪圖,這個圖像的顏色將呈現非常美妙的效果,顏色會從起點顏色到終點顏色過渡。給一張圖, ...
LinearGradient 線性漸變渲染器
LinearGradient中文翻譯過來就是線性漸變的意思。線性漸變通俗來講就是給起點設置一個顏色值如#faf84d,終點設置一個顏色值如#CC423C,然後在一個區域內繪圖,這個圖像的顏色將呈現非常美妙的效果,顏色會從起點顏色到終點顏色過渡。給一張圖,大家直觀感受一下
我們看LinearGradient的API,發現它只有兩個構造方法,非常簡單。
LinearGradient (float x0,
float y0,
float x1,
float y1,
int color0,
int color1,
Shader.TileMode tile)
//x0 和y0是顏色漸變的起點坐標。
//x1和y1是顏色漸變的終點坐標。
//color0是起點顏色值
//color0是終點顏色值。
//tile 就是TileMode類型參數,這個我們上一篇已經講過了。
LinearGradient的用法。
//1 創建LinearGradient對象,並設置它的起點坐標,終點坐標,起點顏色值,終點顏色值,然後設置TileMode
mShader = new LinearGradient(0,0,w,0,Color.parseColor("#faf84d"),
Color.parseColor("#CC423C"), Shader.TileMode.CLAMP);
//2 將Shader賦值給Paint對象。
mPaint.setShader(mShader);
//3 繪製圖形
canvas.drawRect(0,0,w,h/2,mPaint);
用法非常簡單。
LinearGradient還有一個構造方法。
LinearGradient (float x0,
float y0,
float x1,
float y1,
int[] colors,
float[] positions,
Shader.TileMode tile)
需要註意的是,這裡有一個int[] colors
和float[] positions
它們代表什麼意思呢?
實際上LinearGradient除了可以指定起點顏色值和終點顏色值外,還有可以指定許多中間顏色值。就如彩虹一般。而colors[]
數組存放的就是這樣的顏色值組合。大家看看代碼和圖片效果就可能直觀感受到。
//漸變的是一個顏色序列(#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
數組對應,代表了各個顏色值在位置,positions
數組中的值大小範圍從0.0到1.0,0.0代表起點位置,1.0代表終點位置。如果這個數組被置為空的話,顏色就會平均分配。 ,如果這個數組不為空呢?我們結合代碼效果來講解。
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對應的position值是0.0 所以為起點位置。
// #003449對應0.6 所以這個顏色位置起點到終點中間0.6比率的地方。
// #808080對應0.8 這個顏色在0.8比率的地方
// #cc423c對應1.0 這個顏色為終點處的顏色
需要註意的是,position[]
數組中的數組最好是由小到大,這是為什麼呢?它不支持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 環行渲染器
我喜歡稱它為徑向漸變,因為PHOTOSHOP中就對應有徑向漸變的概念。
徑向漸變,所謂徑向就是輻射狀,由中心向四周輻射。
徑向漸變也只有兩個構造方法,基本用法跟線性漸變差不多。
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一樣,這裡也有一個顏色數組和位置數組,意義也是一樣的,stop[]
也可以為null,如果為null的話,color[]
數組的顏色就會平均分配在區域之中。否則,它對應的顏色就會按照比例填充。
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軸出發,以逆時鐘為方向,以掃描360度形成的區域進行顏色的變換。
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)
大家應該也明白這個方法中每個參數的含義。
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);
我們把顏色豐富點,本來想弄成赤橙黃綠青藍紫,結果因為懶,就隨便弄了點,效果如下:
ComposeShader 組合渲染器
混合渲染,在這裡我又開始稱Shader為渲染了,因為ComposeShader不僅僅用於顏色,它能將兩個Shader對象參考Xfermode規則進行顏色混合。
網上的一張圖:
這張圖詳細的解釋了混合模式的組合效果,我機會我也寫一篇相關博文。
再看ComposeShader的兩個構造方法。
ComposeShader (Shader shaderA,
Shader shaderB,
Xfermode mode)
ComposeShader (Shader shaderA,
Shader shaderB,
PorterDuff.Mode mode)
接下來,我們寫代碼驗證一下。
實戰1
- 編寫1個BitmapShader.
- 編寫1個RadiasGradient。
- 將它們進行混合產生新的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. 將它們進行混合產生新的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);
}
}
我們來看看混合後的效果是怎麼樣的。
哇,好夢幻的狗狗。
實戰2 倒影功能
以前剛開始學Android的時候,項目裡面要用到倒影,當時的自己是寫不出來的,好在網上有現成的代碼可以copy。現在我們可以運用ComposeShader來實現這麼一個View。
需求分析
- 倒影與原圖比例為1:4。
- 倒影與原圖之間有5px的間隙。
- 倒影的下邊緣不能太平整了,要儘量跟真實的一致。
好了為了節省篇幅,我只粘貼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);
//將原圖水平翻轉
Bitmap texture = Bitmap.createBitmap(result,0,0,result.getWidth(),result.getHeight(),m,false);
//創建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);
//以混合模式繪製矩形區域,可以獲得倒影效果。
canvas.drawRect(0,0,bmpWidth,reflectionHeight,mPaint);
canvas.restore();
}
效果:
倒影出來了。
Android繪圖Canvas十八般武器之Shader詳解及實戰篇(上)