Android自定義View-Canvas基本操作
一.Canvas基本操作
(1)位移(translate)
translate是座標系的移動,可以為圖形繪製選擇一個合適的座標系。 請注意,位移是基於當前位置移動,而不是每次基於螢幕左上角的(0,0)點移動,如下:
// 在座標原點繪製一個黑色圓形
mPaint.setColor(Color.BLACK);
canvas.translate(200,200);
canvas.drawCircle(0,0,100,mPaint);
// 在座標原點繪製一個藍色圓形
mPaint.setColor(Color.BLUE);
canvas.translate(200,200);
canvas.drawCircle(0,0,100,mPaint);
(2)縮放(scale)
縮放提供了兩個方法,如下:
public void scale (float sx, float sy)
public final void scale (float sx, float sy, float px, float py)
這兩個方法中前兩個引數是相同的分別為x軸和y軸的縮放比例。而第二種方法比前一種多了兩個引數,用來控制縮放中心位置的。
縮放比例(sx,sy)取值範圍詳解:
如果在縮放時稍微注意一下就會發現縮放的中心預設為座標原點,而縮放中心軸就是座標軸,如下:
// 將座標系原點移動到畫布正中心
canvas.translate(mWidth / 2, mHeight / 2);
RectF rect = new RectF(0,-400,400,0); // 矩形區域
mPaint.setColor(Color.BLACK); // 繪製黑色矩形
canvas.drawRect(rect,mPaint);
canvas.scale(0.5f,0.5f); // 畫布縮放
mPaint.setColor(Color.BLUE); // 繪製藍色矩形
canvas.drawRect(rect,mPaint);
接下來我們使用第二種方法讓縮放中心位置稍微改變一下,如下:
// 將座標系原點移動到畫布正中心
canvas.translate(mWidth / 2, mHeight / 2);
RectF rect = new RectF(0,-400,400,0); // 矩形區域
mPaint.setColor(Color.BLACK); // 繪製黑色矩形
canvas.drawRect(rect,mPaint);
canvas.scale(0.5f,0.5f,200,0); // 畫布縮放 <-- 縮放中心向右偏移了200個單位
mPaint.setColor(Color.BLUE); // 繪製藍色矩形
canvas.drawRect(rect,mPaint);
前面兩個示例縮放的數值都是正數,按照表格中的說明,當縮放比例為負數的時候會根據縮放中心軸進行翻轉,下面我們就來實驗一下:
// 將座標系原點移動到畫布正中心
canvas.translate(mWidth / 2, mHeight / 2);
RectF rect = new RectF(0,-400,400,0); // 矩形區域
mPaint.setColor(Color.BLACK); // 繪製黑色矩形
canvas.drawRect(rect,mPaint);
canvas.scale(-0.5f,-0.5f); // 畫布縮放
mPaint.setColor(Color.BLUE); // 繪製藍色矩形
canvas.drawRect(rect,mPaint);
// 將座標系原點移動到畫布正中心
canvas.translate(mWidth / 2, mHeight / 2);
RectF rect = new RectF(0,-400,400,0); // 矩形區域
mPaint.setColor(Color.BLACK); // 繪製黑色矩形
canvas.drawRect(rect,mPaint);
canvas.scale(-0.5f,-0.5f,200,0); // 畫布縮放 <-- 縮放中心向右偏移了200個單位
mPaint.setColor(Color.BLUE); // 繪製藍色矩形
canvas.drawRect(rect,mPaint);
和位移(translate)一樣,縮放也是可以疊加的。
canvas.scale(0.5f,0.5f);
canvas.scale(0.5f,0.1f);
呼叫兩次縮放則 x軸實際縮放為0.5x0.5=0.25 y軸實際縮放為0.5x0.1=0.05
// 將座標系原點移動到畫布正中心
canvas.translate(mWidth / 2, mHeight / 2);
RectF rect = new RectF(-400,-400,400,400); // 矩形區域
for (int i=0; i<=20; i++)
{
canvas.scale(0.9f,0.9f);
canvas.drawRect(rect,mPaint);
}
(3)旋轉(rotate)
旋轉提供了兩種方法:
public void rotate (float degrees)
public final void rotate (float degrees, float px, float py)
和縮放一樣,第二種方法多出來的兩個引數依舊是控制旋轉中心點的。
預設的旋轉中心依舊是座標原點:
// 將座標系原點移動到畫布正中心
canvas.translate(mWidth / 2, mHeight / 2);
RectF rect = new RectF(0,-400,400,0); // 矩形區域
mPaint.setColor(Color.BLACK); // 繪製黑色矩形
canvas.drawRect(rect,mPaint);
canvas.rotate(180); // 旋轉180度 <-- 預設旋轉中心為原點
mPaint.setColor(Color.BLUE); // 繪製藍色矩形
canvas.drawRect(rect,mPaint);
改變旋轉中心位置:
// 將座標系原點移動到畫布正中心
canvas.translate(mWidth / 2, mHeight / 2);
RectF rect = new RectF(0,-400,400,0); // 矩形區域
mPaint.setColor(Color.BLACK); // 繪製黑色矩形
canvas.drawRect(rect,mPaint);
canvas.rotate(180,200,0); // 旋轉180度 <-- 旋轉中心向右偏移200個單位
mPaint.setColor(Color.BLUE); // 繪製藍色矩形
canvas.drawRect(rect,mPaint);
旋轉也是可疊加的
canvas.rotate(180);
canvas.rotate(20);
呼叫兩次旋轉,則實際的旋轉角度為180+20=200度。
(4)快照(save)和回滾(restore)
Q: 為什存在快照與回滾
A:畫布的操作是不可逆的,而且很多畫布操作會影響後續的步驟,例如第一個例子,兩個圓形都是在座標原點繪製的,而因為座標系的移動繪製出來的實際位置不同。所以會對畫布的一些狀態進行儲存和回滾。
與之相關的API:
下面對其中的一些概念和方法進行分析:
狀態棧:
Q:什麼是畫布和圖層?
A:實際上我們看到的畫布是由多個圖層構成的,如下圖:
實際上我們之前講解的繪製操作和畫布操作都是在預設圖層上進行的。
在通常情況下,使用預設圖層就可滿足需求,但是如果需要繪製比較複雜的內容,如地圖(地圖可以有多個地圖層疊加而成,比如:政區層,道路層,興趣點層)等,則分圖層繪製比較好一些。
你可以把這些圖層看做是一層一層的玻璃板,你在每層的玻璃板上繪製內容,然後把這些玻璃板疊在一起看就是最終效果。
SaveFlags
save
save 有兩種方法:
// 儲存全部狀態
public int save ()
// 根據saveFlags引數儲存一部分狀態
public int save (int saveFlags)
restore
狀態回滾,就是從棧頂取出一個狀態然後根據內容進行恢復。
同樣以上面狀態棧圖片為例,呼叫一次restore方法則將狀態棧中第5次取出,根據裡面儲存的狀態進行狀態恢復。
restoreToCount
彈出指定位置以及以上所有狀態,並根據指定位置狀態進行恢復。
以上面狀態棧圖片為例,如果呼叫restoreToCount(2) 則會彈出 2 3 4 5 的狀態,並根據第2次儲存的狀態進行恢復。
getSaveCount
獲取儲存的次數,即狀態棧中儲存狀態的數量,以上面狀態棧圖片為例,使用該函式的返回值為5。
不過請注意,該函式的最小返回值為1,即使彈出了所有的狀態,返回值依舊為1,代表預設狀態。
可以看到第二種方法比第一種多了一個saveFlags引數,使用這個引數可以只儲存一部分狀態,更加靈活,這個saveFlags引數具體可參考上面表格中的內容。
每呼叫一次save方法,都會在棧頂新增一條狀態資訊,以上面狀態棧圖片為例,再呼叫一次save則會在第5次上面載新增一條狀態。
常用格式
雖然關於狀態的儲存和回滾囉嗦了不少,不過大多數情況下只需要記住下面的步驟就可以了:
save(); //儲存狀態
... //具體操作
restore(); //回滾到之前的狀態
相關文章
- Android自定義控制元件之基本原理Android控制元件
- samba 基本配置及自定義控制Samba
- PopWindow:基本使用與自定義PopWindow
- Android 自定義viewAndroidView
- Android 自定義 TabLayoutAndroidTabLayout
- Android: 自定義ViewAndroidView
- Android自定義ToastAndroidAST
- Android 自定義 DrawableAndroid
- android自定義view(自定義數字鍵盤)AndroidView
- android自定義View&自定義ViewGroup(下)AndroidView
- android自定義View&自定義ViewGroup(上)AndroidView
- Android自定義控制元件——自定義屬性Android控制元件
- 事務基本定義操作
- android自定義鍵盤 自定義身份證鍵盤Android
- Android自定義控制元件之自定義屬性Android控制元件
- (Android自定義控制元件)Android自定義狀態提示圖表Android控制元件
- Android 自定義UI元件AndroidUI元件
- android 自定義鍵盤Android
- Android自定義遮罩層Android遮罩
- Android自定義View整合AndroidView
- Android自定義OnTouch事件Android事件
- 自定義Android鍵盤Android
- Android自定義屬性Android
- Android自定義註解Android
- Android 自定義View:深入理解自定義屬性(七)AndroidView
- Android自定義組合控制元件之自定義屬性Android控制元件
- 重拾Android自定義ViewAndroidView
- Android自定義拍照實現Android
- Android自定義View:View(二)AndroidView
- Android 自定義Toast及BUGAndroidAST
- Android自定義ViewGroup(一)AndroidView
- Android自定義view詳解AndroidView
- Android 自定義 view 詳解AndroidView
- Android 實現自定義圓環Android
- Android 自定義標題欄Android
- Android中自定義CheckboxAndroid
- android自定義button樣式Android
- Android自定義action與permission!!!Android