欲先攻其事必先利其器,想要做好自定義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(,,,,mPaint);
//畫出坐标系
drawAxis(canvas,Color.RED);
}
private void drawAxis(Canvas canvas, @ColorInt int color){
mPaint.setStrokeWidth();
mPaint.setColor(color);
canvas.drawLine(,,,,mPaint);
canvas.drawLine(,,,,mPaint);
}
現在我們執行translate方法
canvas.translate(,);
mPaint.setColor(Color.GREEN);
canvas.drawRect(,,,,mPaint);
drawAxis(canvas,Color.RED);
這個沒問題,translate執行後,坐标系的确移動了,現在我們來看rotate(degress)
canvas.rotate();
mPaint.setColor(Color.BLACK);
canvas.drawRect(,,,,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(,);
mPaint.setColor(Color.GREEN);
canvas.drawRect(,,,,mPaint);
//畫出坐标系
drawAxis(canvas,Color.RED);
//移動
canvas.translate(,);
mPaint.setColor(Color.GREEN);
canvas.drawRect(,,,,mPaint);
drawAxis(canvas,Color.RED);
//旋轉
canvas.rotate();
mPaint.setColor(Color.BLACK);
canvas.drawRect(,,,,mPaint);
drawAxis(canvas,Color.BLUE);
//到這已經改變了角度和坐标,我們先複原
canvas.rotate(-);
canvas.translate(-,-);
//再來重新rotate(45,500,500);
mPaint.setColor(Color.GRAY);
canvas.rotate(,,);
canvas.drawRect(,,,,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);
//為看到更好的效果,我們統一将坐标移動到(,)
canvas.translate(,);
mPaint.setColor(Color.GREEN);
canvas.drawRect(,,,,mPaint);
//畫出坐标系
drawAxis(canvas,Color.RED);
canvas.save();
//移動
canvas.translate(,);
mPaint.setColor(Color.GREEN);
canvas.drawRect(,,,,mPaint);
drawAxis(canvas,Color.RED);
//旋轉
canvas.rotate();
mPaint.setColor(Color.BLACK);
canvas.drawRect(,,,,mPaint);
drawAxis(canvas,Color.BLUE);
canvas.restore();
//再次畫圖
mPaint.setColor(Color.GRAY);
canvas.drawRect(,,,,mPaint);
drawAxis(canvas,Color.BLACK);
}
看到沒,在save和restore之間做的圖,直接顯示在螢幕上了,但是在save之前和restore之後的坐标系真沒有改變,是不是恨好奇?
其實,用個ps的人都知道,save和restore之間其實是在新的層上面了,save和restore之外的部分才是同層上做操作,兩層的操作肯定不幹擾了,ok,這下明白了吧!