前言
最近在看自定義View方面的知識,遇到下面一段代碼,由於對旋轉後的繪圖存在疑問,經過多方求證,最後彌補了操作Canvas(旋轉,平移等)認知的錯誤,並得出正確結論:
動畫操作Canvas,其實操作的是臨時座標系,對於已經繪製的圖形部分無效
下面詳細記錄求證過程,以備同仁指正:
建議大家按照代碼繪製看看,繪製對的可以留言,繪製錯了也可以留言,這篇博客讓你理解了嗎?
/**
* 在畫布的 左下角畫圓,
* 中間畫向右箭頭 :旋轉畫布後再畫
* 右上角畫圓:畫布旋轉爲原始方向後再畫
* @param canvas
*/
private void canvasTest(Canvas canvas) {
int width = 200;
int height = 200;
int radius = 10;
int centerX = radius;
int centerY = height - radius;
Paint paint = new Paint();
//畫做左下角的圓
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.BLUE);
paint.setAntiAlias(true);
canvas.drawCircle(centerX, centerY, radius, paint);
// 1.-------------------------------------------------------------
canvas.save();
canvas.rotate(90, width/2, height/2); //以畫布中心爲旋轉點
// canvas.translate(0, -30);
// canvas.scale(1.2f, 1.2f, width/2, height/2);
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(4);
//左線、右線、中線, 把旋轉後的當做新畫布,但x, y 的座標仍是原來方向的,但畫出的圖是旋轉後的
//可以想象爲先在原始畫布上畫,畫好後旋轉
canvas.drawLine(width/2, 0, 0, height/2, paint);
canvas.drawLine(width/2, 0, width, height/2, paint);
canvas.drawLine(width/2, 0, width/2, height, paint);
// 2.----------------------------------------------------
canvas.restore(); //如果不加這一行,那麼下面的那個右上角的圓是 旋轉後的畫布的右上角,而非原始畫布的右上角位置
//右上角畫個圓
int cx2 = width - radius;
int cy2 = radius;
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.RED);
canvas.drawCircle(cx2, cy2, radius, paint);
}
上述的代碼在我求證之初,我得出的圖形是這樣的:
既然是錯誤的,就不多解釋了,免得誤導大家。
下面是正確的繪圖結果:
對比錯誤的和正確的繪圖,不難發現三點差異:
第一:座標系差異(這是個隱形的差異);
第二:旋轉前繪製的圓的差異(旋轉前繪製的圓到底該不該跟隨Canvas旋轉,爲什麼跟隨旋轉的是錯的呢?)
第三:最後一個圓的差異(這個差異其實是因爲第一個原因座標系的差異導致的);
接下來我們就對這三個差異一一解釋:
先說第二個,旋轉前繪製的圓的差異?
這個問題的原因就是我在最前面所說的:旋轉Canvas時,其實旋轉的是臨時的座標系,只對旋轉後的圖形有效,對旋轉前的繪圖無效。
接下來說第一個差異,最後一個圓繪製在canvas.restore()後面,此時的座標系還是旋轉後的座標系嗎?
答案是NO! canvas.restore()方法和canvas.save()方法,細心的朋友可以發現,我在前面特別表示了這兩個方法的位置,canvas.save()寫在旋轉之前,canvas.restore()方法就是將座標系恢復到sava方法調用的地方,所以他們是成雙成對出現的。
總結
動畫操作Canvas,其實操作的是臨時座標系,對於已經繪製的圖形部分無效。而Canvas.restore方法等於是將Canvas動畫操作還原成Save時的狀態
你對這個容易誤解的知識點掌握了嗎?