前言
上一節,學習了Paint的高級用法後,這一節我們將canvas的用法。主要涉及到canvas的繪製座標變換translate,rotate。還沒看過上一節的請點擊這裏:Android_2D繪圖的學習Paint,Canvas(二)。
一,translate
translate在很多語言的圖像處理中都存在,意思是平移,在canvas中,他表示平移座標原點。比如說,你要在一個View的中心點畫一個半徑爲r圓。你可以這樣直接畫:canvas.drawCircle(getWidth()/2,getHeight()/2,r,paint);
也可以使用translate,先移動畫布的座標原點爲view的中心:canvas.trandlate(getWidth()/2,getHeight()/2);
然後再根據新的座標畫出圓即可:canvas.drawCircle(0,0,r,paint);
這裏起始點(0,0)就是view的中心。
二,rotate
rotate是旋轉的意思,在canvas中,大家都說是旋轉畫布,其實更好理解的應該是旋轉座標。比如說,你先畫一個圖形,然後調用rotate方法,將會看到我們的圖像沒有被旋轉。
這裏我做了一個測試,先畫一個藍色的矩形,然後將畫布rotate 30°,再畫一個紅色的矩形,根據上面的原理,應該是紅色的被旋轉了,而藍色的則沒有被旋轉。那麼事實呢,請看下圖:
代碼:
//移動座標原點爲View中心
canvas.translate(getWidth()/2, getHeight()/2);
mPaint.setColor(Color.BLUE);
mPaint.setStyle(Style.STROKE);
//先畫藍色矩形
canvas.drawRect(20, 0, 150, 100, mPaint);
//旋轉畫布
canvas.rotate(30);
//再畫紅色矩形
mPaint.setColor(Color.RED);
canvas.drawRect(20, 0, 150, 100, mPaint);
我們看到正如我們說的一樣,rotate只是旋轉了畫布的座標。
三,save,restroe
save:用來保存Canvas的狀態。save之後,可以調用Canvas的平移、放縮、旋轉、錯切、裁剪等操作。
restore:用來恢復Canvas之前保存的狀態。防止save後對Canvas執行的操作對後續的繪製有影響。
這裏畫兩個矩形來講解使用方法,我們先繪製一個矩形,然後保存當前canvas座標值,再旋轉45度,畫出一個同樣的矩形,爲了區分,顏色不一樣,然後恢復canvas的座標值,繪出x,y座標。
效果:
代碼:
// 矩形寬度
int lenght = dp2px(120);
canvas.translate(getWidth() / 2, getHeight() / 2);
// 第一個黑色矩形
canvas.drawRect(-lenght, -lenght, lenght, lenght, mPaint);
// 保存x軸方向爲3點鐘方向的座標
canvas.save();
// 旋轉座標軸
canvas.rotate(45);
mPaint.setColor(Color.BLUE);
// 第二個藍色矩形
canvas.drawRect(-lenght, -lenght, lenght, lenght, mPaint);
// 恢復座標軸
canvas.restore();
mPaint.setColor(Color.RED);
// 繪製座標軸
canvas.drawLine(0, 0, 300, 0, mPaint);
canvas.drawText("x", 330, 0, textPaint);
canvas.drawLine(0, 0, 0, 300, mPaint);
canvas.drawText("y", 0, 330, textPaint);
這裏當然save和restore是成對出現的,不然缺少意義,當然restore調用次數要少於save的調用次數。
四,簡單的錶盤
學會了translate,rotate,save,restore後,我們實踐一下,繪製一個像這樣的錶盤:
看過這個簡單錶盤,都是由線,三角形,圓,文字繪出的,這些在前面都已經講過,思路都在代碼裏,直接上代碼:
@Override
protected void onDraw(Canvas canvas) {
// 半徑
int radius = dp2px(100);
// 修改座標軸原點
canvas.translate(getWidth() / 2, getHeight() / 2);
// 保存座標軸的狀態
canvas.save();
// 畫一個圓
canvas.drawCircle(0, 0, radius, mPaint);
// 逆時針旋轉60度,這樣 1 刻度就能在正確的位置
canvas.rotate(-60);
// 畫出刻度:一共有60個刻度,從第一個刻度開始,每5個刻度爲長刻度
for (int i = 0; i < 60; i++) {
if (i % 5 == 0) {
// 繪製長刻度
canvas.drawLine(radius, 0, radius + dp2px(20), 0, mPaint);
/* 繪製數字,因爲方向的問題,所以這裏還需要旋轉平移座標軸 */
// 保存-60的座標軸
canvas.save();
// 將座標軸移動到該畫數字的位置
canvas.translate(radius + dp2px(25), 0);
// 旋轉座標,可以讓數字朝向圓心
canvas.rotate(90);
String text = String.valueOf(i / 5 + 1);
// 測量字體的寬度,使其居中
int width = (int) textPaint.measureText(text);
canvas.drawText(text, -width / 2, 0, textPaint);
// 恢復後:座標原點還是在View的中心,x軸方向爲1點鐘方向
canvas.restore();
} else {
// 繪製短刻度
canvas.drawLine(radius, 0, radius + dp2px(10), 0, mPaint);
}
canvas.rotate(360 / 60f);
}
// 恢復後:座標原點還是在View的中心,x軸方向爲3點鐘方向
canvas.restore();
// 畫出指針
canvas.drawLine(0, 0, 0, -dp2px(60), mPaint);
Path path = new Path();
path.moveTo(3, -dp2px(60));
path.lineTo(-3, -dp2px(60));
path.lineTo(0, -dp2px(63));
path.close();
canvas.drawPath(path, mPaint);
// 繪製文字
String text = "canvas clock";
int width = (int) textPaint.measureText(text);
canvas.drawText(text, -width / 2, dp2px(50), textPaint);
}
主要考慮一下數字方向的繪製,網上很多都沒有考慮到這個問題。