Android Canvas繪圖詳解

Android中使用圖形處理引擎,2D部分是android SDK內部自己提供,3D部分是用Open GL ES 1.0

大部分2D使用的api都在android.graphics和android.graphics.drawable包中。他們提供了圖形處理相關 的: Canvas、ColorFilter、Point(點)和RetcF(矩形)等,還有一些動畫相關的:AnimationDrawable、 BitmapDrawable和TransitionDrawable等。以圖形處理來說,我們最常用到的就是在一個View上畫一些圖片、形狀或者自定 義的文本內容,這里我們都是使用Canvas來實現的。你可以獲取View中的Canvas對象,繪制一些自定義形狀,然后調用View. invalidate方法讓View重新刷新,然后繪制一個新的形狀,這樣達到2D動畫效果。下面我們就主要來了解下Canvas的使用方法。

Canvas對象的獲取方式有兩種:一種我們通過重寫View.onDraw方法,View中的Canvas對象會被當做參數傳遞過來,我們操作這個Canvas,效果會直接反應在View中。另一種就是當你想創建一個Canvas對象時使用的方法:

1

2Bitmap b = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);

Canvas c =newCanvas(b);

上 面代碼創建了一個尺寸是100*100的Bitmap,使用它作為Canvas操作的對象,這時候的Canvas就是使用創建的方式。當你使用創建的 Canvas在bitmap上執行繪制方法后,你還可以將繪制的結果提交給另外一個Canvas,這樣就可以達到兩個Canvas協作完成的效果,簡化邏 輯。但是android SDK建議使用View.onDraw參數里提供的Canvas就好,沒必要自己創建一個新的Canvas對象。接下來我們看看Canvas提供我們哪些 繪制圖形的方法。我們創建一個自定義View對象,使用onDraw方法提供的Canvas進行繪制圖形。

CanvasDemoActivity.java:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47package com.android777.demo.uicontroller.graphics;

import android.app.Activity;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.os.Bundle;

import android.view.View;

public class CanvasDemoActivity extends Activity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(newCustomView1(this));

}

/**

* 使用內部類 自定義一個簡單的View

* @author Administrator

*

*/

class CustomView1 extends View{

Paint paint;

public CustomView1(Context context) {

super(context);

paint =newPaint();//設置一個筆刷大小是3的黃色的畫筆

paint.setColor(Color.YELLOW);

paint.setStrokeJoin(Paint.Join.ROUND);

paint.setStrokeCap(Paint.Cap.ROUND);

paint.setStrokeWidth(3);

}

//在這里我們將測試canvas提供的繪制圖形方法

@Override

protected void onDraw(Canvas canvas) {

}

}

}

執行結果是一片黑色的區域,因為在自定義的CustomView1中,我們沒有做任何的繪制操作。canvas提供的繪制圖形的方法都是以draw開頭的,我們可以查看api:

從上面方法的名字看來我們可以知道Canvas可以繪制的對象有:

弧 線(arcs);

// 繪制弧線區域

RectF rectF = new RectF(0, 0, 100, 100);

// RectF設置四個參數(分別是距離左多少,距離上多少,距離右多少 , 距離下多少);

canvas.drawArc(rectF, 0, 90, false, paint);

------------------------------------------------------------------------------------------------------------------------------

填充顏色(argb和color);

Bitmap;

圓(circle和oval);

// drawCircle (圓的中心被吸引的x坐標 , 坐標中心的圓來繪制 , 半徑的圓來繪制(旋轉多少度) , paint對象 );

canvas.drawCircle(100, 100, 90, paint);

-------------------------------------------------------------------------------------------------------------------------------

點(point);

// drawPoint(該點X位置 , 該點的Y位置 ?, paint對象);

canvas.drawPoint(500, 500, paint);

-------------------------------------------------------------------------------------------------------------------------------

線(line);

// drawLine (該線路的起始點的x坐標 , 該線路的起始點的Y坐標 , 線的終點距離屏幕的x坐標的距離 , 該線的長度 , paint對象);

canvas.drawLine(0, 0, 100, 1000, paint);

-------------------------------------------------------------------------------------------------------------------------------

矩形(Rect);

//RectF (該圓距離X的距離,該園距離Y的距離,該圓的寬 ,該圓的上);

RectF rectF = new RectF(10, 10, 100, 100);

canvas.drawOval(rectF, paint);

-------------------------------------------------------------------------------------------------------------------------------

圖片(Picture);

圓角矩形 (RoundRect);

RectF rectF = new RectF(50, 50, 100, 100);

canvas.drawRoundRect(rectF,

30, //x軸的半徑

30, //y軸的半徑

paint);

文本(text);

// drawPosText (要顯示的文本, 文本每一個字母的位置(通過float類型的集合) , paint對象);

canvas.drawPosText("Android", new float[]{10,10,20,20,30,30,40,40,50,50,60,60,70,70}, paint);

-------------------------------------------------------------------------------------------------------------------------------

頂點(Vertices);

路徑(path);

Path path = new Path(); // 定義一條路徑

/*

* 設置下一個輪廓線的起點(×,)。

*

* @param x x坐標的開始一個新的輪廓

*

* @param Y坐標,開始一種新的輪廓

*/

path.moveTo(10, 10); // 移動到 坐標10,10

/*

* 從最后一個點到指定點(x)加一條線。如果沒有moveto()調用了這個輪廓,第一點是自動設置為(0,0)

*/

path.lineTo(60, 60);

path.lineTo(200, 80);

path.lineTo(10, 10);

canvas.drawPath(path, paint);

-------------------------------------------------------------------------------------------------------------------------------

通過組合這些對象我們可以畫出一些簡單有趣 的界面出來,但是光有這些功能還是不夠的,如果我要畫一個儀表盤(數字圍繞顯示在一個圓圈中)呢? 幸好Android還提供了一些對Canvas位置轉換的方法:rorate、scale、translate、skew(扭曲)等,而且它允許你通過獲 得它的轉換矩陣對象(getMatrix方法,不知道什么是轉換矩陣?看這里) 直接操作它。這些操作就像是雖然你的筆還是原來的地方畫,但是畫紙旋轉或者移動了,所以你畫的東西的方位就產生變化。為了方便一些轉換操作,Canvas 還提供了保存和回滾屬性的方法(save和restore),比如你可以先保存目前畫紙的位置(save),然后旋轉90度,向下移動100像素后畫一些 圖形,畫完后調用restore方法返回到剛才保存的位置。下面我們就演示下canvas的一些簡單用法:

1

2

3

4protected void onDraw(Canvas canvas) {

canvas.drawCircle(100, 100, 90, paint);

}

效果是:

1

2

3

4

5

6

7

8

9

10

11

12

13

14@Override

protected void onDraw(Canvas canvas) {

//繪制弧線區域

RectF rect =newRectF(0, 0, 100, 100);

canvas.drawArc(rect,//弧線所使用的矩形區域大小

0,//開始角度

90,//掃過的角度

false,//是否使用中心

paint);

}

使用下面的代碼:

1

2

3

4

5

6

7

8

9

10

11

12

13protected void onDraw(Canvas canvas) {

//繪制弧線區域

RectF rect =newRectF(0, 0, 100, 100);

canvas.drawArc(rect,//弧線所使用的矩形區域大小

0,//開始角度

90,//掃過的角度

true,//是否使用中心

paint);

}

兩 圖對比我們可以發現,當 drawArcs(rect,startAngel,sweepAngel,useCenter,paint)中的useCenter為false時,弧 線區域是用弧線開始角度和結束角度直接連接起來的,當useCenter為true時,是弧線開始角度和結束角度都與中心點連接,形成一個扇形。

1

2

3

4

5protected void onDraw(Canvas canvas) {

canvas.drawColor(Color.BLUE);

}

canvas.drawColor是直接將View顯示區域用某個顏色填充滿。

1

2

3

4

5

6

7@Override

protected void onDraw(Canvas canvas) {

//畫一條線

canvas.drawLine(10, 10, 100, 100, paint);

}

Canvas.drawOval:

1

2

3

4

5

6

7

8

9@Override

protected void onDraw(Canvas canvas) {

//定義一個矩形區域

RectF oval =newRectF(0,0,200,300);

//矩形區域內切橢圓

canvas.drawOval(oval, paint);

}

canvas.drawPosText:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18@Override

protected void onDraw(Canvas canvas) {

//按照既定點 繪制文本內容

canvas.drawPosText("Android777",newfloat[]{

10,10,//第一個字母在坐標10,10

20,20,//第二個字母在坐標20,20

30,30,//....

40,40,

50,50,

60,60,

70,70,

80,80,

90,90,

100,100

}, paint);

}

canvas.drawRect:

1

2

3

4

5

6

7

8

9

10@Override

protected void onDraw(Canvas canvas) {

RectF rect =newRectF(50, 50, 200, 200);

canvas.drawRect(rect, paint);

}

}

canvas.drawRoundRect:

1

2

3

4

5

6

7

8

9

10

11@Override

protected void onDraw(Canvas canvas) {

RectF rect =newRectF(50, 50, 200, 200);

canvas.drawRoundRect(rect,

30,//x軸的半徑

30,//y軸的半徑

paint);

}

canvas.drawPath:

1

2

3

4

5

6

7

8

9

10

11

12@Override

protected void onDraw(Canvas canvas) {

Path path =newPath();//定義一條路徑

path.moveTo(10, 10);//移動到 坐標10,10

path.lineTo(50, 60);

path.lineTo(200,80);

path.lineTo(10, 10);

canvas.drawPath(path, paint);

}

canvas.drawTextOnPath:

1

2

3

4

5

6

7

8

9

10

11

12

13@Override

protected void onDraw(Canvas canvas) {

Path path =newPath();//定義一條路徑

path.moveTo(10, 10);//移動到 坐標10,10

path.lineTo(50, 60);

path.lineTo(200,80);

path.lineTo(10, 10);

//????????? canvas.drawPath(path, paint);

canvas.drawTextOnPath("Android777開發者博客", path, 10, 10, paint);

}

位置轉換方法,canvas.rorate和canvas.translate:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46@Override

protected void onDraw(Canvas canvas) {

paint.setAntiAlias(true);

paint.setStyle(Style.STROKE);

canvas.translate(canvas.getWidth()/2, 200);//將位置移動畫紙的坐標點:150,150

canvas.drawCircle(0, 0, 100, paint);//畫圓圈

//使用path繪制路徑文字

canvas.save();

canvas.translate(-75, -75);

Path path =newPath();

path.addArc(newRectF(0,0,150,150), -180, 180);

Paint citePaint =newPaint(paint);

citePaint.setTextSize(14);

citePaint.setStrokeWidth(1);

canvas.drawTextOnPath("http://www.android777.com", path, 28, 0, citePaint);

canvas.restore();

Paint tmpPaint =newPaint(paint);//小刻度畫筆對象

tmpPaint.setStrokeWidth(1);

float? y=100;

int count = 60;//總刻度數

for(int i=0 ; i

if(i%5 == 0){

canvas.drawLine(0f, y, 0, y+12f, paint);

canvas.drawText(String.valueOf(i/5+1), -4f, y+25f, tmpPaint);

}else{

canvas.drawLine(0f, y, 0f, y +5f, tmpPaint);

}

canvas.rotate(360/count,0f,0f);//旋轉畫紙

}

//繪制指針

tmpPaint.setColor(Color.GRAY);

tmpPaint.setStrokeWidth(4);

canvas.drawCircle(0, 0, 7, tmpPaint);

tmpPaint.setStyle(Style.FILL);

tmpPaint.setColor(Color.YELLOW);

canvas.drawCircle(0, 0, 5, tmpPaint);

canvas.drawLine(0, 10, 0, -65, paint);

}

上面幾個例子基本已經將常用的canvas.draw*方法測試過了,我們結合一些事件,做一些有用戶交互的應用:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67package com.android777.demo.uicontroller.graphics;

import java.util.ArrayList;

import android.app.Activity;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.PointF;

import android.os.Bundle;

import android.view.MotionEvent;

import android.view.View;

public class CanvasDemoActivity extends Activity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(newCustomView1(this));

}

/**

* 使用內部類 自定義一個簡單的View

* @author Administrator

*

*/

class CustomView1 extends View{

Paint paint;

private ArrayList graphics =newArrayList();

PointF point;

public CustomView1(Context context) {

super(context);

paint =newPaint();//設置一個筆刷大小是3的黃色的畫筆

paint.setColor(Color.YELLOW);

paint.setStrokeJoin(Paint.Join.ROUND);

paint.setStrokeCap(Paint.Cap.ROUND);

paint.setStrokeWidth(3);

}

@Override

public boolean onTouchEvent(MotionEvent event) {

graphics.add(newPointF(event.getX(),event.getY()));

invalidate();//重新繪制區域

returntrue;

}

//在這里我們將測試canvas提供的繪制圖形方法

@Override

protected void onDraw(Canvas canvas) {

for(PointF point : graphics) {

canvas.drawPoint(point.x, point.y, paint);

}

//????????? super.onDraw(canvas);

}

}

}

當用戶點擊時將出現一個小點,拖動時將畫出一條用細點組成的虛線:

canvas的應用

canva還可以制作很多自定義控件,比如google日歷的monthview就是用canvas繪制出來的,github上有很多使用canva的項目,所有的圖表庫都是用canvas繪制的。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,001評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,786評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,986評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,204評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,964評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,354評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,410評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,554評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,106評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,918評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,093評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,648評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,342評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,755評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,009評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,839評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,107評論 2 375

推薦閱讀更多精彩內容

  • ¥開啟¥ 【iAPP實現進入界面執行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程,因...
    小菜c閱讀 6,489評論 0 17
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,681評論 25 708
  • 導航 Android Paint之顏色過濾器 Paint之shader(圖像渲染) Paint之PathEffec...
    侯蛋蛋_閱讀 4,636評論 0 5
  • 版權聲明:本文為博主原創文章,未經博主允許不得轉載 前言 Canvas 本意是畫布的意思,然而將它理解為繪制工具一...
    cc榮宣閱讀 41,602評論 1 47
  • 昨晚臨睡前,閨蜜發了幾張她在老家拍的照片給我,看完后,居然害我一整晚都在夢里刨地瓜。 今早上班,我將照片給同事看,...
    李茗閱讀 1,553評論 27 23