Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android基礎入門教程——8.3.16 Canvas API詳解(Part 1)

Android基礎入門教程——8.3.16 Canvas API詳解(Part 1)

編輯:關於Android編程

Android基礎入門教程——8.3.16 Canvas API詳解(Part 1)

標簽(空格分隔): Android基礎入門教程


本節引言:

前面我們花了13小節詳細地講解了Android中Paint類大部分常用的API,本節開始我們來講解
Canvas(畫板)的一些常用API,我們在Android基礎入門教程——8.3.1 三個繪圖工具類詳解
中已經列出了我們可供調用的一些方法,我們分下類:

drawXxx方法族:以一定的坐標值在當前畫圖區域畫圖,另外圖層會疊加,
即後面繪畫的圖層會覆蓋前面繪畫的圖層。 clipXXX方法族:在當前的畫圖區域裁剪(clip)出一個新的畫圖區域,這個
畫圖區域就是canvas對象的當前畫圖區域了。比如:clipRect(new Rect()),
那麼該矩形區域就是canvas的當前畫圖區域 getXxx方法族:獲得與Canvas相關一些值,比如寬高,屏幕密度等。 save(),restore(),saveLayer(),restoreToCount()等保存恢復圖層的方法 translate(平移),scale(縮放),rotate(旋轉),skew(傾斜)

當然還有其他一些零散的方法,嗯,從本節開始我會挑一些感覺有點意思的API來進行學習~
而本節先給大家帶來的是translate(平移),scale(縮放),rotate(旋轉),skew(傾斜)
以及save(),restore()的詳解!
官方API文檔:Canvas
另外我們先要明確Canvas中X軸與Y軸的方向:

title=


1.translate(平移)

方法translate(float dx, float dy)
解析:平移,將畫布的坐標原點向左右方向移動x,向上下方向移動y,canvas默認位置在(0,0)
參數:dx為水平方向的移動距離,dy為垂直方向的移動距離

使用示例

        for(int i=0; i < 5; i++) {
            canvas.drawCircle(50, 50, 50, mPaint);
            canvas.translate(100, 100);
        }

運行效果

title=


2.rotate(旋轉)

方法rotate(float degrees) / rotate(float degrees, float px, float py)
解析:圍繞坐標原點旋轉degrees度,值為正順時針
參數:degrees為旋轉角度,px和py為指定旋轉的中心點坐標(px,py)

使用示例

        Rect rect = new Rect(50,0,150,50);
        canvas.translate(200, 200);
        for(int i = 0; i < 36;i++){
            canvas.rotate(10);
            canvas.drawRect(rect, mPaint);
        }

運行效果

title=

代碼分析

這裡我們先調用了translate(200,200)將canvas的坐標原點移向了(200,200),再進行繪制,所以我們
繪制的結果可以完整的在畫布上顯示出來,假如我們是為rotate設置了(10,200,200),會是這樣一個
結果:

title=

有疑問是吧,這個涉及到Canvas多圖層的概念,等等會講~


3.scale(縮放)

方法scale(float sx, float sy) / scale(float sx, float sy, float px, float py)
解析:對畫布進行縮放
參數:sx為水平方向縮放比例,sy為豎直方向的縮放比例,px和py我也不知道,小數為縮小
整數為放大

使用示例

        canvas.drawBitmap(bmp,0,0,mPaint);
        canvas.scale(0.8f, 0.8f);
        canvas.drawBitmap(bmp, 0, 0, mPaint);
        canvas.scale(0.8f, 0.8f);
        canvas.drawBitmap(bmp,0,0,mPaint);

運行效果

title=


4.skew(傾斜)

方法skew(float sx, float sy)
解析:傾斜,也可以譯作斜切,扭曲
參數:sx為x軸方向上傾斜的對應角度,sy為y軸方向上傾斜的對應角度,兩個值都是tan值哦!
都是tan值!都是tan值!比如要在x軸方向上傾斜60度,那麼小數值對應:tan 60 = 根號3 = 1.732!

使用示例

        canvas.drawBitmap(bmp,0,0,mPaint);
        canvas.translate(200, 200);
        canvas.skew(0.2f,-0.8f);
        canvas.drawBitmap(bmp,0,0,mPaint);

運行效果

title=


5.Canvas圖層的概念以及save()和restore()詳解

我們一般喜歡稱呼Canvas為畫布,童鞋們一直覺得Canvas就是一張簡單的畫紙,那麼我想
問下多層的動畫是怎麼用canvas來完成的?上面那個translate平移的例子,為什麼
drawCircle(50, 50, 50, mPaint); 參考坐標一直是(50,50)那為何會出現這樣的效果?
有疑惑的童鞋可能是一直將屏幕的概念與Canvas的概念混淆了,下面我們來還原下
調用translate的案發現場:

title=

如圖,是畫布坐標原點的每次分別在x,y軸上移動100;那麼假如我們要重新回到(0,0)
點處繪制新的圖形呢?怎麼破,translate(-100,-100)的慢慢地平移回去?不會真的這麼
糾結吧…
title=
好吧,不賣關子了,我們可以在做平移變換之前將當前canvas的狀態進行保存,其實Canvas為
我們提供了圖層(Layer)的支持,而這些Layer(圖層)是按”棧結構”來進行管理的

title=

當我們調用save()方法,會保存當前Canvas的狀態然後作為一個Layer(圖層),添加到Canvas棧中,
另外,這個Layer(圖層)不是一個具體的類,就是一個概念性的東西而已!
而當我們調用restore()方法的時候,會恢復之前Canvas的狀態,而此時Canvas的圖層棧
會彈出棧頂的那個Layer,後繼的Layer來到棧頂,此時的Canvas回復到此棧頂時保存的Canvas狀態!
簡單說就是**:save()往棧壓入一個Layer,restore()彈出棧頂的一個Layer,這個Layer代表Canvas的
狀態!也就是說可以save()多次,也可以restore()多次,但是restore的調用次數不能大於**save
否則會引發錯誤!這是網上大部分的說法,不過實際測試中並沒有出現這樣的問題,即使我restore的
次數多於save,也沒有出現錯誤~目測是系統改了,等下測給大家看~
title=
來來來,寫個例子驗證下save和restore的作用!

寫個例子

例子代碼

        canvas.save();  //保存當前canvas的狀態

        canvas.translate(100, 100);
        canvas.drawCircle(50, 50, 50, mPaint);

        canvas.restore();  //恢復保存的Canvas的狀態
        canvas.drawCircle(50, 50, 50, mPaint);

運行結果

title=

不用說什麼了吧,代碼和結果已經說明了一切,接著我們搞得復雜點,來一發
多個save()和restore()!

例子代碼

        canvas.save();

        canvas.translate(300, 300);
        canvas.drawBitmap(bmp, 0, 0, mPaint);
        canvas.save();

        canvas.rotate(45);
        canvas.drawBitmap(bmp, 0, 0, mPaint);
        canvas.save();

        canvas.rotate(45);
        canvas.drawBitmap(bmp, 0, 0, mPaint);
        canvas.save();

        canvas.translate(0, 200);
        canvas.drawBitmap(bmp, 0, 0, mPaint);

運行結果

title=

結果分析

首先平移(300,300)畫圖,然後旋轉45度畫圖,再接著旋轉45度畫圖,接著平移(0,200),
期間每次畫圖前都save()一下,看到這裡你可能有個疑問,最後這個平移不是y移動200
麼,怎麼變成向左了?嘿嘿,我會告訴你rotate()旋轉的是整個坐標軸麼?坐標軸的
變化:

title=

嗯,rotate()弄懂了是吧,那就行,接著我們來試試restore咯~我們在最後繪圖的前面
加兩個restore()!

        canvas.restore();
        canvas.restore();
        canvas.translate(0, 200);
        canvas.drawBitmap(bmp, 0, 0, mPaint);

運行結果

title=

不說什麼,自己體會,再加多個restore()

title=

有點意思,再來,繼續加restore()

title=

嗯,好像不可以再寫restore了是吧,因為我們只save了四次,按照網上的說法,
這會報錯的,真的是這樣嗎?這裡我們調用Canvas給我們提供的一個獲得當前棧中
有多少個Layer的方法:getSaveCount();然後在save()和restore()的前後都
加一個Log將棧中Layer的層數打印出來:

title=

結果真是喜聞樂見,畢竟實踐出真知,可能是Canvas改過吧,或者其他原因,這裡
要看源碼才知道了,時間關系,這裡我們知道下restore的次數可以比save多就好了,
但是還是建議restore的次數還是少於save,以避免造成不必要的問題~
至於進棧和出棧的流程我就不話了,筆者自己動筆畫畫,非常容易理解!


6.saveLayer()與restoreToCount()講解

其實這兩個方法和save以及restore大同小異,只是在後者的基礎上多了一些東東而已,
比如saveLayer(),有下面多個重載方法:

title=

你可以理解為save()方法保存的是整個Canvas,而saveLayer()則可以選擇性的保存某個區域的狀態,
另外,我們看到餐宿和中有個:int saveFlags,這個是設置改保存那個對象的!可選值有:

標記 說明 ALL_SAVE_FLAG 保存全部的狀態 CLIP_SAVE_FLAG 保存裁剪的某個區域的狀態 CLIP_TO_LAYER_SAVE_FLAG 保存預先設置的范圍裡的狀態 FULL_COLOR_LAYER_SAVE_FLAG 保存彩色塗層 HAS_ALPHA_LAYER_SAVE_FLAG 不透明圖層保存 MATRIX_SAVE_FLAG Matrix信息(translate,rotate,scale,skew)的狀態保存

PS:上述說明有點問題,筆者英語水平低,可能說錯,如果有知道的,請務必指正提出,謝謝~
這裡我們寫個例子來驗證下:我們選用CLIP_TO_LAYER_SAVE_FLAG模式來寫個例子

實現代碼

        RectF bounds = new RectF(0, 0, 400, 400);
        canvas.saveLayer(bounds, mPaint, Canvas.CLIP_TO_LAYER_SAVE_FLAG);
        canvas.drawColor(getResources().getColor(R.color.moss_tide));
        canvas.drawBitmap(bmp, 200, 200, mPaint);
        canvas.restoreToCount(1);
        canvas.drawBitmap(bmp, 300, 200, mPaint);

運行結果

title=

關於saveLayer()後面用到再詳解研究吧~這裡先知道個大概~

接著到這個restoreToCount(int),這個更簡單,直接傳入要恢復到的Layer層數,
直接就跳到對應的那一層,同時會將該層上面所有的Layer踢出棧,讓該層
成為棧頂~!比起你寫多個restore()方便快捷多了~


 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved