欲先攻其事必先利其器,想要做好自定義view,就必須先將canvas掌握,面對canvas,我們在心中必先要有個這樣的意識,canvas是無限大的,而之所以我們看到了只有屏幕大小,那是屏幕給我們帶來的迷惑,廢話不多說,今天我們主要來聊canvas中常用用法,translate,rotate,save,restore等功能,估計大夥都覺得這幾個功能很簡單嘛,網上隨便一搜一大把,其實到了一些真正細節的東西都含糊其詞了。
是不是大家之前一直存在一下觀點:
translate移動改變了canvas的座標,rotate(degress)改變了canvas的座標角度,而rotate(degress,x,y)效果相當於translate(x,y)+rotate(degress)但沒有改變canvas座標?真相是否如此,咱們看代碼和圖
先圖個矩形且畫出座標:
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.GREEN);
canvas.drawRect(0,0,100,100,mPaint);
//畫出座標系
drawAxis(canvas,Color.RED);
}
private void drawAxis(Canvas canvas, @ColorInt int color){
mPaint.setStrokeWidth(10);
mPaint.setColor(color);
canvas.drawLine(0,0,400,0,mPaint);
canvas.drawLine(0,0,0,400,mPaint);
}
現在我們執行translate方法
canvas.translate(500,500);
mPaint.setColor(Color.GREEN);
canvas.drawRect(0,0,100,100,mPaint);
drawAxis(canvas,Color.RED);
這個沒問題,translate執行後,座標系的確移動了,現在我們來看rotate(degress)
canvas.rotate(45);
mPaint.setColor(Color.BLACK);
canvas.drawRect(0,0,100,100,mPaint);
drawAxis(canvas,Color.BLUE);
座標系也的確旋轉了,那我們接着來看下rotate(45,x,y)和translate(x,y)+rotate(45)效果是不是一樣?前者是否改變了原來的座標系呢?
其實translate(x,y)+rotate(45)的效果前面我們已經看到了,他的確既改變座標又改變了角度,接下來我們看看rotate(45,x,y)是不是和前者重合?
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//爲看到更好的效果,我們統一將座標移動到(500,500)
canvas.translate(500,500);
mPaint.setColor(Color.GREEN);
canvas.drawRect(0,0,100,100,mPaint);
//畫出座標系
drawAxis(canvas,Color.RED);
//移動
canvas.translate(500,500);
mPaint.setColor(Color.GREEN);
canvas.drawRect(0,0,100,100,mPaint);
drawAxis(canvas,Color.RED);
//旋轉
canvas.rotate(45);
mPaint.setColor(Color.BLACK);
canvas.drawRect(0,0,100,100,mPaint);
drawAxis(canvas,Color.BLUE);
//到這已經改變了角度和座標,我們先復原
canvas.rotate(-45);
canvas.translate(-500,-500);
//再來重新rotate(45,500,500);
mPaint.setColor(Color.GRAY);
canvas.rotate(45,500,500);
canvas.drawRect(0,0,100,100,mPaint);
drawAxis(canvas,Color.BLACK);
}
爲了更好地看到效果,我們將初始座標移動至(500,500),效果如下:
什麼情況,怎麼rotate(45)+translate(500,500)和rotate(45,500,500)效果完全不同呢,而且後者畫的東西完全不符合邏輯嘛,是不是顛覆我們的想法?究竟rotate(45,500,500)做了什麼?直接上源碼:
public final void rotate(float degrees, float px, float py) {
translate(px, py);
rotate(degrees);
translate(-px, -py);
}
看到沒,源碼是在移動座標旋轉角度後,再回復座標,此時還能恢復不?答案是肯定不能的,除非先恢復座標系的角度,然後再恢復,那才能恢復到原來的座標點,現在知道原因了吧。
接着我們來看下,save和restore,這玩意究竟什麼用呢?聽說夾在這兩個玩意中間的任何操作都沒有改變原始座標系,究竟是不是這樣?直接上demo
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//爲看到更好的效果,我們統一將座標移動到(500,500)
canvas.translate(500,500);
mPaint.setColor(Color.GREEN);
canvas.drawRect(0,0,100,100,mPaint);
//畫出座標系
drawAxis(canvas,Color.RED);
canvas.save();
//移動
canvas.translate(500,500);
mPaint.setColor(Color.GREEN);
canvas.drawRect(0,0,100,100,mPaint);
drawAxis(canvas,Color.RED);
//旋轉
canvas.rotate(45);
mPaint.setColor(Color.BLACK);
canvas.drawRect(0,0,100,100,mPaint);
drawAxis(canvas,Color.BLUE);
canvas.restore();
//再次畫圖
mPaint.setColor(Color.GRAY);
canvas.drawRect(0,0,60,60,mPaint);
drawAxis(canvas,Color.BLACK);
}
看到沒,在save和restore之間做的圖,直接顯示在屏幕上了,但是在save之前和restore之後的座標系真沒有改變,是不是恨好奇?
其實,用個ps的人都知道,save和restore之間其實是在新的層上面了,save和restore之外的部分纔是同層上做操作,兩層的操作肯定不干擾了,ok,這下明白了吧!