本文轉自 http://blog.csdn.net/jiangwei0910410003/article/details/42640665,稍有修改,感謝分享!
在實現自定義View之前,有必要掌握Android中畫圖的相關類的使用方法,這是自定義各種酷炫界面的基礎。主要使用到以下兩個類:
畫筆:Paint
畫布:Canvas
1. Android中的Paint和Canvas的概念和使用方法
Android中的Paint和Canvas的概念是很簡單的,就是用畫筆在畫布上進行繪製,沒什麼難度的,只要拿到畫筆Paint和畫布Canvas對象就可以進行操作了。當然Canvas對象提供了很多繪製圖形的方法,
1.1 Paint對象
新建一個Paint畫筆對象
Paint p = new Paint();
p.setColor(Color.RED);// 設置畫筆顏色爲紅色
p.setAntiAlias(true);// 設置畫筆的鋸齒效果。 true是去除,大家一看效果就明白了
注:關於這個鋸齒,其實很好理解,如果沒有鋸齒效果,畫出來的圓形就很光滑,有鋸齒看上去的圓形很粗糙的。但是默認情況下,畫筆是有鋸齒的。之所以這樣,是因爲在沒有鋸齒效果的情況下,繪製圖形效率會比有鋸齒效果低,所以系統考慮了效率問題,就把默認值設置成有鋸齒了,在實際繪圖過程中需要衡量一下的。
對於畫筆對象,它有很多的屬性:
- void setARGB(int a, int r, int g, int b) //設置Paint對象顏色,參數一爲alpha透明通道
- void setAlpha(int a) //設置alpha不透明度,範圍爲0~255
- void setAntiAlias(boolean aa) //是否抗鋸齒,默認值是false
- void setColor(int color) //設置顏色,這裏Android內部定義的有Color類包含了一些常見顏色定義
- void setFakeBoldText(boolean fakeBoldText) //設置僞粗體文本
- void setLinearText(boolean linearText) //設置線性文本
- PathEffect setPathEffect(PathEffect effect) //設置路徑效果
- Rasterizer setRasterizer(Rasterizer rasterizer) //設置光柵化
- Shader setShader(Shader shader) //設置陰影 ,我們在後面會詳細說一下Shader對象的
- void setTextAlign(Paint.Align align) //設置文本對齊
- void setTextScaleX(float scaleX) //設置文本縮放倍數,1.0f爲原始
- void setTextSize(float textSize) //設置字體大小
Typeface setTypeface(Typeface typeface) //設置字體,Typeface包含了字體的類型,粗細,還有傾斜、顏色等
注:
Paint mp = new paint();
mp.setTypeface(Typeface.DEFAULT_BOLD)常用的字體類型名稱還有:
- Typeface.DEFAULT //常規字體類型
- Typeface.DEFAULT_BOLD //黑體字體類型
- Typeface.MONOSPACE //等寬字體類型
- Typeface.SANS_SERIF //sans serif字體類型
- Typeface.SERIF //serif字體類型
除了字體類型設置之外,還可以爲字體類型設置字體風格,如設置粗體:
Paint mp = new Paint();
Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD);
p.setTypeface( font );常用的字體風格名稱還有:
- Typeface.BOLD //粗體
- Typeface.BOLD_ITALIC //粗斜體
- Typeface.ITALIC //斜體
- Typeface.NORMAL //常規
void setUnderlineText(boolean underlineText) //設置下劃線
void setStyle(Style style) //設置畫筆樣式
常用的樣式:- Paint.Style.FILL
- Paint.Style.STROKE
- Paint.Style.FILL_AND_STROKE
這裏的FILL和STROKE兩種方式用的最多,他們的區別也很好理解的,FILL就是填充的意思,STROKE就是空心的意思,只有 圖形的輪廓形狀,內部是空的。
void setStrokeWidth(float width) //在畫筆的樣式爲STROKE的時候,圖形的輪廓寬度
1.2 Canvas對象
對於畫布對象Canvas我們是從onDraw方法中獲取到的,我們在自定義視圖的時候都會繼承View類,然後在他的onDraw方法中拿到Canvas對象,進行各種繪製了。下面就來看一下各種繪製的方法:
1.2.1 畫圓(drawCircle)
想一下,如果畫出一個圓形的話需要哪些要素,學過幾何的同學都知道:圓心座標+半徑 就可以確定一個圓了
canvas.drawCircle(120, 20, 20, p); //這裏的p是之前講的Paint對象
- 參數一:圓心的x座標
- 參數二:圓心的y座標
- 參數三:圓的半徑
- 參數四:畫筆對象
1.2.2 畫直線(drawLine)
畫出一個直線,需要起點座標+終點座標 就可以確定一條直線了
canvas.drawLine(60, 40, 100, 40, p);// 畫直線
- 參數一:起始點的x座標
- 參數二:起始點的y座標
- 參數三:終點的x座標
- 參數四:終點的y座標
- 參數五:畫筆對象
1.2.3 畫矩形(drawRect)
RectF oval1=new RectF(150,20,180,40);
canvas.drawRect(oval1, p);
- 參數一:矩形對象
- 參數二:畫筆對象
這裏說一下RectF的相關知識:在繪圖中這個對象是十分重要的,它表示的是一個矩形,它有四個參數:
left, top, right, bottom
這四個值是相對於設備屏幕的起始點開始的。
比如上面的這個矩形,是這樣:
RectF oval1=new RectF(150,20,180,40);
矩形的左上角的座標是:(150,20)
矩形的右下角的座標是:(180,30)
那麼我們就知道這個矩形的寬是:180-150=30;高是:40-20=20
注:還有一個與RectF相關的對象:Rect,它也是四個參數,和RectF唯一的區別就是,Rect中的參數是float類型的,RectF中的參數是int類型的
1.2.4 畫圓角矩形(drawRoundRect)
RectF oval3 = new RectF(80, 260, 200, 300);// 新建一個矩形
canvas.drawRoundRect(oval3, 20, 15, p);
- 參數一:矩形大小
- 參數二:圓角的x半徑
- 參數三:圓角的y半徑
- 參數四:畫筆對象
1.2.5 畫橢圓(drawOval)
畫一個橢圓,需要的要素是長軸長度+短軸長度
RectF oval1=new RectF(150,20,180,40); //新建一個橢圓外接矩形
canvas.drawOval(oval2, p);
- 參數一:橢圓的外接矩形
- 參數二:畫筆對象
一個矩形可以確定一個橢圓,這個矩形和橢圓外接
橢圓的長軸就是矩形的寬,短軸就是矩形的高
這樣就可以確定一個橢圓了,如果想畫一個圓形,用這種方式也是可以的,只要把RectF設置成正方形就可以了。
1.2.6 畫弧線/扇形(drawArc)
畫出一個弧線需要的要素是,起始的弧度+弧線的弧度+外圍的矩形大小
這個和上面畫橢圓很相似的,就相當於在他的基礎上多了 起始弧度+弧線的弧度
p.setStyle(Paint.Style.STROKE);//設置空心
RectF oval1=new RectF(150,20,180,40);
canvas.drawArc(oval1, 180, 180, false, p);//弧形
- 參數一:外接矩形
- 參數二:弧線開始的弧度
- 參數三:弧線的弧度
- 參數四:是一個boolean類型的參數:true的時候畫扇形,是false的時候畫弧線
- 參數五:畫筆對象
1.2.7 畫三角形/多邊形(drawPath)
畫三角形/多邊形需要的要素,能確定多邊形的形狀最重要的因素就是角,這些角的頂點就是一個座標
Path path = new Path();
path.moveTo(80, 200);// 此點爲多邊形的起點
path.lineTo(120, 250);
path.lineTo(80, 250);
path.close(); // 使這些點構成封閉的多邊形
canvas.drawPath(path, p);
這裏需要介紹一下Path對象,這個對象顧名思義,是路徑的意思,它有兩個參數:
- 參數一:x座標
- 參數二:y座標
路徑是由多個點相連接的。所以Path提供了兩個方法:moveTo()和lineTo()
- moveTo方法的作用是設置路徑的開始點,如果沒有這個方法的調用的話,系統默認的開始點是(0,0)點
- lineTo方法就是將路徑的上一個座標點和當前座標點進行連接,或者可以認爲設置多邊形的每個角的頂點的座標
那麼對於三角形,需要三個點即可。
這個畫三角形其實用上面的畫直線的方法也可以實現的,反過來也是,我們用Path對象也是可以畫出一條直線的,那麼他們的本質區別是:
- 繪製路徑方式的焦點是角的頂點(座標點)
- 繪製直線的方式的焦點是邊(長度)
1.2.8 畫點(drawPoint)
canvas.drawPoint(60, 390, p);//畫一個點
canvas.drawPoints(new float[]{60,400,65,400,70,400}, p);//畫多個點
這裏有兩個方法:
drawPoint(畫一個點)
- 參數一:點的x座標
- 參數二:點的y座標
- 參數三:畫筆對象
drawPoints(畫多個點)
- 參數一:多個點的數組
- 參數二:畫筆對象
1.2.9 畫貝塞爾曲線(drawPath)
這種曲線其實我們在開發過程中很少用到,在圖形學中繪製貝塞爾曲線的時候,需要的要素是:起始點+控制點+終點
Path path2=new Path();
path2.moveTo(100, 320);//設置Path的起點
path2.quadTo(150, 310, 170, 400); //設置貝塞爾曲線的控制點座標和終點座標
canvas.drawPath(path2, p);//畫出貝塞爾曲線
它也是使用Path對象的。不過用的是quadTo()方法
- 參數一:控制點的x座標
- 參數二:控制點的y座標
- 參數三:終點的x座標
- 參數四:終點的y座標
需要注意的是,這裏是調用moveTo方法來確定開始座標,如果沒有調用這個方法,起始點座標默認是:(0,0)
1.2.10 繪製圖片(drawBitmap)
可以將bitmap對象貼到畫布上,也是很常用的一種用法
//畫圖片,就是貼圖
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
canvas.drawBitmap(bitmap, 250,360, p);
- 參數一:圖片Bitmap對象
- 參數二:圖片相對於設備屏幕的left值
- 參數二:圖片相對於設備屏幕的top值
注:可以把圖片認爲是一個矩形,因爲圖片本身是有長度和寬度的,所以這裏只需要矩形的左上角的座標點,就可以確定這張圖片在屏幕中的位置了。
上面就介紹完了Paint對象和Canvas對象,他們兩個是自定義視圖的基礎,所以這部分內容一定要掌握,當然這兩個對象沒什麼難度的,這些東西是很簡單的。
下面來看一下實例代碼:
package com.example.drawpathdemo;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.View;
public class DrawView extends View {
public DrawView(Context context) {
super(context);
}
public DrawView(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
}
@SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
/*
* 方法 說明
* drawRect 繪製矩形 drawCircle 繪製圓形 drawOval 繪製橢圓 drawPath 繪製任意多邊形
* drawLine 繪製直線 drawPoin 繪製點
*/
// 創建畫筆
Paint p = new Paint();
p.setColor(Color.RED);// 設置紅色
canvas.drawText("畫圓:", 10, 20, p);// 畫文本
canvas.drawCircle(60, 20, 10, p);// 小圓
p.setAntiAlias(true);// 設置畫筆的鋸齒效果。 true是去除,一看效果就明白了
canvas.drawCircle(120, 20, 20, p);// 大圓
canvas.drawText("畫線及弧線:", 10, 60, p);
p.setColor(Color.GREEN);// 設置綠色
canvas.drawLine(60, 40, 100, 40, p);// 畫線
canvas.drawLine(110, 40, 190, 80, p);// 斜線
//畫笑臉弧線
p.setStyle(Paint.Style.STROKE);//設置空心
RectF oval1=new RectF(150,20,180,40);
canvas.drawArc(oval1, 180, 180, false, p);//小弧形
oval1.set(190, 20, 220, 40);
canvas.drawArc(oval1, 180, 180, false, p);//小弧形
oval1.set(160, 30, 210, 60);
canvas.drawArc(oval1, 0, 180, false, p);//小弧形
canvas.drawText("畫矩形:", 10, 80, p);
p.setColor(Color.GRAY);// 設置灰色
p.setStyle(Paint.Style.FILL);//設置填滿
canvas.drawRect(60, 60, 80, 80, p);// 正方形
canvas.drawRect(60, 90, 160, 100, p);// 長方形
canvas.drawText("畫扇形和橢圓:", 10, 120, p);
/* 設置漸變色 這個正方形的顏色是改變的 */
Shader mShader = new LinearGradient(0, 0, 100, 100,
new int[] { Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW,
Color.LTGRAY }, null, Shader.TileMode.REPEAT); // 一個材質,打造出一個線性梯度沿著一條線。
p.setShader(mShader);
RectF oval2 = new RectF(60, 100, 200, 240);// 設置個新的長方形,掃描測量
canvas.drawArc(oval2, 200, 130, true, p);
// 畫弧,第一個參數是RectF:該類是第二個參數是角度的開始,第三個參數是多少度,第四個參數是true的時候畫扇形,是false的時候畫弧線
//畫橢圓,把oval改一下
oval2.set(210,100,250,130);
canvas.drawOval(oval2, p);
canvas.drawText("畫三角形:", 10, 200, p);
// 繪製這個三角形,你可以繪製任意多邊形
Path path = new Path();
path.moveTo(80, 200);// 此點爲多邊形的起點
path.lineTo(120, 250);
path.lineTo(80, 250);
path.close(); // 使這些點構成封閉的多邊形
canvas.drawPath(path, p);
//你可以繪製很多任意多邊形,比如下面畫六連形
p.reset();//重置
p.setColor(Color.LTGRAY);
p.setStyle(Paint.Style.STROKE);//設置空心
Path path1=new Path();
path1.moveTo(180, 200);
path1.lineTo(200, 200);
path1.lineTo(210, 210);
path1.lineTo(200, 220);
path1.lineTo(180, 220);
path1.lineTo(170, 210);
path1.close();//封閉
canvas.drawPath(path1, p);
/*
* Path類封裝複合(多輪廓幾何圖形的路徑
* 由直線段*、二次曲線,和三次方曲線,也可畫以油畫。drawPath(路徑、油漆),要麼已填充的或撫摸
* (基於油漆的風格),或者可以用於剪斷或畫畫的文本在路徑。
*/
//畫圓角矩形
p.setStyle(Paint.Style.FILL);//充滿
p.setColor(Color.LTGRAY);
p.setAntiAlias(true);// 設置畫筆的鋸齒效果
canvas.drawText("畫圓角矩形:", 10, 260, p);
RectF oval3 = new RectF(80, 260, 200, 300);// 設置個新的長方形
canvas.drawRoundRect(oval3, 20, 15, p);//第二個參數是x半徑,第三個參數是y半徑
//畫貝塞爾曲線
canvas.drawText("畫貝塞爾曲線:", 10, 310, p);
p.reset();
p.setStyle(Paint.Style.STROKE);
p.setColor(Color.GREEN);
Path path2=new Path();
path2.moveTo(100, 320);//設置Path的起點
path2.quadTo(150, 310, 170, 400); //設置貝塞爾曲線的控制點座標和終點座標
canvas.drawPath(path2, p);//畫出貝塞爾曲線
//畫點
p.setStyle(Paint.Style.FILL);
canvas.drawText("畫點:", 10, 390, p);
canvas.drawPoint(60, 390, p);//畫一個點
canvas.drawPoints(new float[]{60,400,65,400,70,400}, p);//畫多個點
//畫圖片,就是貼圖
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
canvas.drawBitmap(bitmap, 250,360, p);
}
}
運行效果:
2. Android中重要的概念:渲染對象Shader
參考資料:http://blog.csdn.net/t12x3456/article/details/10473225
爲什麼把Shader對象單獨拿出來說一下呢?因爲這個對象在對於我們處理圖形特效的時候是非常有用
Shader的直接子類:
- BitmapShader : 位圖圖像渲染
- LinearGradient : 線性渲染
- RadialGradient : 環形渲染
- SweepGradient : 掃描漸變渲染/梯度渲染
- ComposeShader : 組合渲染,可以和其他幾個子類組合起來使用
是不是很像Animation及其子類的關係(AlphaAnimation,RotateAnimation,ScaleAnimation,TranslateAnimation, AnimationSet)
既有具體的渲染效果,也有渲染效果的組合
Shader類作爲基類主要是返回繪製時顏色的橫向跨度。其子類可以作用於Piant。通過 paint.setShader(Shader shader);來實現一些渲染效果。只作用於圖形不作用於bitmap。
構造方法爲默認的構造方法。
枚舉:
emun Shader.TileMode
定義了平鋪的3種模式:
- static final Shader.TileMode CLAMP//邊緣拉伸.
- static final Shader.TileMode MIRROR//在水平方向和垂直方向交替景象, 兩個相鄰圖像間沒有縫隙.
- static final Shader.TillMode REPETA//在水平方向和垂直方向重複擺放,兩個相鄰圖像間有縫隙縫隙.
方法:
boolean getLoaclMatrix(Matrix localM); //如果shader有一個非本地的矩陣將返回true。localM:如果不爲null將被設置爲shader的本地矩陣.
void setLocalMatrix(Matrix localM); //設置shader的本地矩陣,如果localM爲空將重置shader的本地矩陣。
2.1 Shader的使用
使用步驟總結爲:
- 構建Shader對象
- 通過Paint的setShader方法設置渲染對象
- 設置渲染對象
- 繪製時使用這個Paint對象
2.1.1 BitmapShader的使用:
public BitmapShader(Bitmap bitmap,Shader.TileMode tileX,Shader.TileMode tileY)
調用這個方法來產生一個畫有一個位圖的渲染器(Shader)。
參數:
- bitmap 在渲染器內使用的位圖
- tileX The tiling mode for x to draw the bitmap in. 在位圖上X方向渲染器平鋪模式
- tileY The tiling mode for y to draw the bitmap in. 在位圖上Y方向渲染器平鋪模式
- TileMode:
- CLAMP :如果渲染器超出原始邊界範圍,會複製範圍內邊緣染色。
- REPEAT :橫向和縱向的重複渲染器圖片,平鋪。
- MIRROR :橫向和縱向的重複渲染器圖片,這個和REPEAT重複方式不一樣,他是以鏡像方式平鋪。
實例代碼:
package com.tony.shader;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.util.AttributeSet;
import android.view.View;
public class BitmapShaderView extends View {
private BitmapShader bitmapShader = null;
private Bitmap bitmap = null;
private Paint paint = null;
private ShapeDrawable shapeDrawable = null;
private int BitmapWidth = 0;
private int BitmapHeight = 0;
public BitmapShaderView(Context context) {
super(context);
// 得到圖像
bitmap = ((BitmapDrawable) getResources().getDrawable(R.drawable.cat))
.getBitmap();
BitmapWidth = bitmap.getWidth();
BitmapHeight = bitmap.getHeight();
// 構造渲染器BitmapShader
bitmapShader = new BitmapShader(bitmap, Shader.TileMode.MIRROR,Shader.TileMode.REPEAT);
}
public BitmapShaderView(Context context,AttributeSet set) {
super(context, set);
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
//將圖片裁剪爲橢圓形
//構建ShapeDrawable對象並定義形狀爲橢圓
shapeDrawable = new ShapeDrawable(new OvalShape());
//得到畫筆並設置渲染器
shapeDrawable.getPaint().setShader(bitmapShader);
//設置顯示區域
shapeDrawable.setBounds(20, 20,BitmapWidth-140,BitmapHeight);
//繪製shapeDrawable
shapeDrawable.draw(canvas);
}
}
效果圖:
2.1.2 LinearGradient的使用
相信很多人都看過歌詞同步的效果, 一是豎直方向的滾動,另一方面是水平方面的歌詞顏色漸變點亮效果,這種效果怎麼做呢? 這就需要用到LinearGradient線性渲染,下面還是先看具體的使用:
LinearGradient有兩個構造函數;
public LinearGradient(float x0, float y0, float x1, float y1, int[] colors, float[] positions,Shader.TileMode tile)
參數:
- float x0: 漸變起始點x座標
- float y0:漸變起始點y座標
- float x1:漸變結束點x座標
- float y1:漸變結束點y座標
- int[] colors:顏色 的int 數組
- float[] positions: 相對位置的顏色數組,可爲null, 若爲null,顏色沿漸變線均勻分佈
- Shader.TileMode tile: 渲染器平鋪模式
public LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1,Shader.TileMode tile)
參數:
- float x0: 漸變起始點x座標
- float y0:漸變起始點y座標
- float x1:漸變結束點x座標
- float y1:漸變結束點y座標
- int color0: 起始漸變色
- int color1: 結束漸變色
- Shader.TileMode tile: 渲染器平鋪模式
實例代碼:
package com.tony.shader;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.graphics.Shader;
import android.view.View;
public class LinearGradientView extends View {
private LinearGradient linearGradient = null;
private Paint paint = null;
public LinearGradientView(Context context)
{
super(context);
linearGradient = new LinearGradient(0, 0, 100, 100, new int[] {
Color.YELLOW, Color.GREEN, Color.TRANSPARENT, Color.WHITE }, null,
Shader.TileMode.REPEAT);
paint = new Paint();
}
public LinearGradientView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
//設置渲染器
paint.setShader(linearGradient);
//繪製圓環
canvas.drawCircle(240, 360, 200, paint);
}
}
效果圖:
關於這個渲染對象,需要多解釋一下,因爲這個渲染器用的地方很多:
具體看一下他的構造方法中的參數含義:
Paint paint2 = new Paint();
paint2.setColor(Color.BLACK);
paint2.setStrokeWidth(5);
paint2.setStyle(Paint.Style.FILL);
Shader mShader = new LinearGradient(0,0,100,100,
Color.RED,
Color.BLUE, Shader.TileMode.CLAMP);
paint2.setShader(mShader);
Rect rect = new Rect();
rect.left = 0;
rect.right = 300;
rect.top = 0;
rect.bottom = 300;
canvas.drawRect(rect, paint2);
效果圖:
把構造方法中的值改變一下:
Shader mShader = new LinearGradient(0,0,300,300,
Color.RED,
Color.BLUE, Shader.TileMode.CLAMP);
再看一下效果:
這裏我們就看到了構造方法中的四個參數值的含義了:
- 參數一:渲染開始點的x座標
- 參數二:渲染開始點的y座標
- 參數三:渲染結束點的x座標
- 參數四:渲染結束點的y座標
因爲這裏設置矩形的大小是高和寬都是300
所以,從第一個例子中可以看出:渲染結束點之後的顏色是最後一種顏色:藍色
再將代碼改變一下:
Shader mShader = new LinearGradient(0,0,300,0,
Color.RED,
Color.BLUE, Shader.TileMode.CLAMP);
效果:
結束點的座標設置成:(300,0)就實現了橫向渲染
當然也可以實現縱向渲染的,這裏就不演示了。
再修改一下代碼:
Shader mShader = new LinearGradient(0,0,100,100,
Color.RED,
Color.BLUE, Shader.TileMode.MIRROR);
效果:
將渲染模式改成:Shader.TileMode.MIRROR 鏡像模式了
看到效果,當渲染結束點是(100,100)的時候,後面還是會繼續渲染的,而且是相反的(就像照鏡子一樣),然後再渲染一下,每次渲染的效果都是和之前的相反。因爲矩形的長度和寬度都是300,所以這裏會渲染三次。
再將代碼修改一下:
Shader mShader = new LinearGradient(0,0,100,100,
Color.RED,
Color.BLUE, Shader.TileMode.REPEAT);
效果圖:
將渲染模式改成:Shader.TileMode.REPEAT 重複模式了
這裏看到也是會渲染三次的,但是和鏡像模式不同的是,它們的渲染方向都是一致的。
從上面的三種渲染模式可以看出來,之後渲染的結束點小於渲染圖形的大小的時候纔會有效果的,如果把大小改一下:
Shader mShader = new LinearGradient(0,0,300,300,
Color.RED,
Color.BLUE, Shader.TileMode.REPEAT);
效果圖:
效果和Shader.TileMode.CLAMP一樣的。
這種渲染器用的地方還是很多的,後面介紹長條漸變的SeekBar就要用到這種渲染器
2.1.3 RadialGradient的使用
圓形渲染器,這種渲染器很好理解,就是同心圓的渲染機制
public RadialGradient(float x, float y, float radius, int[] colors, float[] positions,Shader.TileMode tile)
參數:
- float x: 圓心X座標
- float y: 圓心Y座標
- float radius: 半徑
- int[] colors: 渲染顏色數組
- floate[] positions: 相對位置數組,可爲null, 若爲null,可爲null,顏色沿漸變線均勻分佈
- Shader.TileMode tile:渲染器平鋪模式
public RadialGradient(float x, float y, float radius, int color0, int color1,Shader.TileMode tile)
參數:
- float x: 圓心X座標
- float y: 圓心Y座標
- float radius: 半徑
- int color0: 圓心顏色
- int color1: 圓邊緣顏色
- Shader.TileMode tile:渲染器平鋪模式
實例代碼:
package com.tony.shader;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RadialGradient;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.View;
public class RadialGradientView extends View {
Paint mPaint = null;
// 環形漸變渲染
Shader mRadialGradient = null;
public RadialGradientView(Context context) {
super(context);
//1.圓心X座標2.Y座標3.半徑 4.顏色數組 5.相對位置數組,可爲null 6.渲染器平鋪模式
mRadialGradient = new RadialGradient(240, 240, 240, new int[] {
Color.YELLOW, Color.GREEN, Color.TRANSPARENT, Color.RED }, null,
Shader.TileMode.REPEAT);
mPaint = new Paint();
}
public RadialGradientView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
// 繪製環形漸變
mPaint.setShader(mRadialGradient);
// 第一個,第二個參數表示圓心座標
// 第三個參數表示半徑
canvas.drawCircle(240, 360, 200, mPaint);
}
}
效果:
關於這個圓形渲染器,可以實現水波紋的效果:
package com.tony.testshader;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RadialGradient;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
/**
* 水波紋效果
* @author tony
*
*/
public class WaterRipplesView extends View {
Shader mBitmapShader = null;
Bitmap mBitmapPn = null;
Paint mPaint = null;
Shader mRadialGradient = null;
Canvas mCanvas = null;
ShapeDrawable mShapeDrawable = null;
public WaterRipplesView(Context context) {
super(context);
// 初始化工作
Bitmap bitmapTemp = ((BitmapDrawable) getResources().getDrawable(
R.drawable.leaf)).getBitmap();
DisplayMetrics dm = getResources().getDisplayMetrics();
// 創建與當前使用的設備窗口大小一致的圖片
mBitmapPn = Bitmap.createScaledBitmap(bitmapTemp, dm.widthPixels,
dm.heightPixels, true);
// 創建BitmapShader object
mBitmapShader = new BitmapShader(mBitmapPn, Shader.TileMode.REPEAT,
Shader.TileMode.MIRROR);
mPaint = new Paint();
}
public WaterRipplesView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
// 將圖片裁剪爲橢圓型
// 創建ShapeDrawable object,並定義形狀爲橢圓
mShapeDrawable = new ShapeDrawable(new OvalShape());// OvalShape:橢圓
// 設置要繪製的橢圓形的東西爲ShapeDrawable圖片
mShapeDrawable.getPaint().setShader(mBitmapShader);
// 設置顯示區域
mShapeDrawable.setBounds(0, 0, mBitmapPn.getWidth(),
mBitmapPn.getHeight());
// 繪製ShapeDrawable
mShapeDrawable.draw(canvas);
if (mRadialGradient != null) {
mPaint.setShader(mRadialGradient);
canvas.drawCircle(0, 0, 1000, mPaint);
}
}
// @覆寫觸摸屏事件
public boolean onTouchEvent(MotionEvent event) {
// @設置alpha通道(透明度)
mPaint.setAlpha(400);
mRadialGradient = new RadialGradient(event.getX(), event.getY(), 48,
new int[] { Color.WHITE, Color.TRANSPARENT },null, Shader.TileMode.REPEAT);
// @重繪
postInvalidate();
return true;
}
}
重寫觸發方法,獲取觸發點座標,設置渲染器的圓形座標,即可
效果:
2.1.4 SweepGradient的使用
梯度渲染器,或者是扇形選擇器,和雷達掃描效果差不多
public SweepGradient(float cx, float cy, int[] colors, float[] positions)
參數:
- cx: 渲染中心點x 座標
- cy: 渲染中心y 點座標
- colors: 圍繞中心渲染的顏色數組,至少要有兩種顏色值
- positions: 相對位置的顏色數組,可爲null, 若爲null,可爲null,顏色沿漸變線均勻分佈
public SweepGradient(float cx, float cy, int color0, int color1)
參數:
- cx: 渲染中心點x 座標
- cy: 渲染中心點y 座標
- color0: 起始渲染顏色
- color1: 結束渲染顏色
實例代碼:
package com.tony.testshader;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.util.AttributeSet;
import android.view.View;
public class SweepGradientView extends View {
Paint mPaint = null;
// 梯度渲染
Shader mSweepGradient = null;
public SweepGradientView(Context context) {
super(context);
// 創建SweepGradient對象
// 第一個,第二個參數中心座標
// 後面的參數與線性渲染相同
mSweepGradient = new SweepGradient(240, 360, new int[] {Color.CYAN,Color.DKGRAY,Color.GRAY,Color.LTGRAY,Color.MAGENTA,
Color.GREEN,Color.TRANSPARENT, Color.BLUE }, null);
mPaint = new Paint();
}
public SweepGradientView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 繪製梯度漸變
mPaint.setShader(mSweepGradient);
canvas.drawCircle(240, 360, 200, mPaint);
}
}
效果圖:
這種渲染器用到的地方很多,下一篇文章中的自定義圓形漸變的SeekBar就會用到這種渲染器
到此,自定義View需要使用的一些界面繪製相關類就介紹完,接下來將開始正式進入自定義View
注: 考慮到篇幅和內容相關性,將原博分成兩篇,再次感謝原作者! 原文鏈接:http://blog.csdn.net/jiangwei0910410003/article/details/42640665