Android自定義View你所要知道的(二):Canvas解析

在2D繪圖中,Canvas和Paint能畫出各種各樣漂亮的圖形。再配合着滑動和動畫特效,就能做出非常炫酷的View。這篇文章是對使用Canvas繪圖使用的總結。更像是對API的中文翻譯。。

先從最小的畫點開始:

public void drawPoint(float x, float y,Paint paint);
public void drawPoints(float[] pts, Paint paint);
public void drawPoints(float[] pts, int offset, int count,Paint paint);

參數:相對View自身的x,y座標和畫筆(Paint)。drawPoints()畫多個點,以數組的形式存儲多個點的座標。

對座標不是很瞭解的,可以參考我的上一篇文章: Android自定義View你所要知道的(一):座標系

單個點:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawPoint(100,100,mTestPaint);
}

效果圖:


在創建Paint對象的時候記得設置寬度,否則畫出來看不見,同理點的大小也是由Paint的寬度決定的。

畫多個點:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    float[] coordinates = new float[]{100,100,200,200,300,300,400,400,500,500};
    canvas.drawPoints(coordinates,mTestPaint);
}
效果:


在第三個方法,drawPoints(float[] pts, int offset, int count,Paint paint)中多了兩個參數,offset和count。

offset參數指的是,前面pts座標集中要從頭要跳過的個數;count參數則是跳過後要執行幾個值。我們以上面那串代碼爲例,傳入offset和count 的值。

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    float[] coordinates = new float[]{100,100,200,200,300,300,400,400,500,500};
    canvas.drawPoints(coordinates,2,8,mTestPaint);
}

跳過前面兩個,100,100,執行後面全部8個。效果如下:



繪製線

public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint);
public void drawLines(float[] pts, Paint paint);
public void drawLines(float[] pts, int offset, int count, Paint paint);

畫線和畫點有着異曲同工之妙,不同的是一條線,他是由兩個座標點來確定的。

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawLine(100,100,500,500,mTestPaint);
}
效果:



畫多條線,offset,count參數都和畫點一樣,參考多試試。

繪製矩形

public void drawRect(float left, float top, float right, float bottom,Paint paint) 
public void drawRect(Rect r, Paint paint)
public void drawRect(RectF rect, Paint paint)

參數都比較簡單,通過左上右下的距離來構建一個矩形,同時也來確定繪製出來圖形的大小。而下面兩個方法是直接傳入一個矩形對象來完成的,構造方法參數都一樣。

public Rect(int left, int top, int right, int bottom)
public RectF(float left, float top, float right, float bottom)
相比可以看出,Rect和RectF的區別在於RectF參數爲float類型,更加精確。

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawRect(100,100,500,500,mTestPaint);
}

效果:

                

其實繪製矩形也像是通過確定2個座標點來畫的,如上右圖。

構建Rect對象來畫矩形:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    Rect rect = new Rect(0,0,300,300);
    canvas.drawRect(rect,mTestPaint);
}

參數都一樣,效果:

                   

當然,我們可以將畫筆掏空(paint.setStyle(Paint.Style.STOKE)),這樣畫出來只有邊線,效果如右上圖.

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mTestPaint.setStyle(Paint.Style.STROKE);
Rect rect = new Rect(0,0,300,300);
canvas.drawRect(rect,mTestPaint);
}

繪製圓

public void drawCircle(float cx, float cy, float radius, Paint paint);

參數傳入圓心的座標和半徑就可以了。如下:

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mTestPaint.setStyle(Paint.Style.STROKE);
canvas.drawCircle(500,500,200,mTestPaint);
}

                      


繪製橢圓

public void drawOval(RectF oval, Paint paint);

public void drawOval(float left, float top, float right, float bottom, Paint paint);

參數比較簡單,直接看代碼效果

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mTestPaint.setStyle(Paint.Style.STROKE);
canvas.drawOval(200,200,600,500,mTestPaint);
}


相信大家現在對距離傳參和直接構建Rect矩形對象來繪製圖形都比較瞭解。下面接不做過多的介紹了。


繪製圓角矩形

public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, Paint paint)
public void drawRoundRect(RectF rect, float rx, float ry, Paint paint)

參數就比繪製矩形多了兩個rx,ry。用來確定4個角,兩個方向x,y的圓角半徑。

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawRoundRect(200,200,600,600,90,90,mTestPaint);
}
效果:



繪製弧形

public void drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, Paint paint);
public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint);

相比前面所涉及到的參數出現了3個陌生的參數,startAngle,sweepAngle,usecenter。通過字面意思可以看出,開始的角度以及要掃描覆蓋多少角度,boolean類型的usecenter直譯是使用中心,待會試試兩種不同的效果。

代碼:

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawArc(300,300,800,800,0,300,true,mTestPaint);
}

先傳入2個座標距離,來確定弧形的大小,從0°開始沿着順時針方向繪製300度。

繪製出來的效果:

                   

我們將usecenter改爲false,效果  


兩者之間的差距就在於,usecenter爲true時會根據 弧形中心點  ,起始角度點,掃描度數結束的點來構建弧形。爲false時,直接以起始點和結束點來繪製弧形。這就很好的理解參數名字。

將畫筆掏空後,沒有顏色填充的效果。

protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mTestPaint.setStyle(Paint.Style.STROKE);
canvas.drawArc(300,300,800,800,0,300,false,mTestPaint);
}

                      

利用Path繪製多邊形

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mTestPaint.setStyle(Paint.Style.STROKE);
Path path = new Path();
path.moveTo(200,200);
path.lineTo(200,500);
path.lineTo(500,500);
path.lineTo(500,200);
path.close();
canvas.drawPath(path,mTestPaint);
}

效果:

                        

通過4個點的座標來繪製了一個正方形,close()方法的作用在於將第一個點和最後一個點連接,對圖形進行閉合。

也可以在Path上添加其他的圖形:


path.addCircle(350,350,80,Path.Direction.CW);
path.addCircle(350,350,40,Path.Direction.CW);

最後一個參數是枚舉類型,就兩個常量,CW和CCW。代表着順時針和逆時針方向。

效果:



繪製文字

public void drawText(String text, int start, int end, float x, float y, Paint paint)

public void drawText(char[] text, int index, int count, float x, float y, Paint paint)

public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint)

public void drawText(String text, float x, float y, Paint paint)

參數都比較簡單,文字內容,座標位置,文字內容中開始索引,結束索引, count參數:確定開始索引位置後需要從文字內容中執行幾個數據;

需要值得注意的是,Java中取一段範圍的數據,start和end。start包括這個索引的數據,而end不包括這個索引的數據。

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mTestPaint.setTextSize(50);
canvas.drawText("你好,歡迎來到英雄聯盟!",0,5,500,500,mTestPaint);
}

效果:


將多個文字放在不同的點上:

public void drawPosText(String text,float[] pos, Paint paint)

public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint)

pos數組參數,點的座標。index和count跟上面說的一樣起始索引和數量。

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mTestPaint.setTextSize(50);
char[] data = {'歡','迎','來','到','英','雄','聯','盟'};
float[] pos = {200,200,300,300,400,400,500,500,600,600,700,700,800,800,900,900};
canvas.drawPosText(data,0,8,pos,mTestPaint);
}

效果:



前面我們說過path裏再添加其他圖形,這兒我們沿着Path添加的圖形來繪製的文字:

public void drawTextOnPath( String text, Path path, float hOffset, float vOffset, Paint paint);

public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset, float vOffset,Paint paint);

代碼實現以下

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mTestPaint.setTextSize(50);
mTestPaint.setStyle(Paint.Style.STROKE);
Path path = new Path();
path.addCircle(500,500,200, Path.Direction.CCW);
canvas.drawPath(path,mTestPaint);
canvas.drawTextOnPath("歡迎來到英雄聯盟",path,0,200,mTestPaint);
}

不同的參數hOffset,vOffset;Offset跟繪製弧形startAngle參數是一個概念,起始角度位置。vOffset指的是距離添加圖形邊的偏移量。

效果:

                         


Canvas的剪裁功能:



可以直接剪裁一個矩形的圖片,或者使用path構建多邊形來剪裁。

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mTestPaint.setTextSize(50);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.yjx);
Path path = new Path();
path.moveTo(200,200);
path.lineTo(200,800);
path.lineTo(800,800);
path.close();
canvas.clipPath(path);
canvas.drawBitmap(bitmap,0,0,mTestPaint);
}

效果:

                                              原圖:  



差不多到這兒了。

更多解析:

android canvas常用的方法解析(一)







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章