HenCoder Android 开发进阶:自定义 View 1-4 Canvas 对绘制的辅助 clipXXX() 和 Matrix
這期是 HenCoder 自定義繪制的第 1-4 期:Canvas 對繪制的輔助——范圍裁切和幾何變換。
之前的內容在這里:?
HenCoder Android 開發進階 自定義 View 1-1 繪制基礎?
HenCoder Android 開發進階 自定義 View 1-2 Paint 詳解?
HenCoder Android 開發進階 自定義 View 1-3 文字的繪制
如果你沒聽說過 HenCoder,可以先看看這個:?
HenCoder:給高級 Android 工程師的進階手冊
簡介
一圖勝千言,一視頻勝千圖,走你:
如果你是在手機上看的,可以點這里去 B 站看原視頻。
1 范圍裁切
范圍裁切有兩個方法:?clipRect()?和?clipPath()。裁切方法之后的繪制代碼,都會被限制在裁切范圍內。
1.1 clipRect()
使用很簡單,直接應用:
canvas.clipRect(left, top, right, bottom); canvas.drawBitmap(bitmap, x, y, paint);記得要加上?Canvas.save()?和?Canvas.restore()?來及時恢復繪制范圍,所以完整代碼是這樣的:
canvas.save(); canvas.clipRect(left, top, right, bottom); canvas.drawBitmap(bitmap, x, y, paint); canvas.restore();1.2 clipPath()
其實和 clipRect() 用法完全一樣,只是把參數換成了?Path?,所以能裁切的形狀更多一些:
canvas.save(); canvas.clipPath(path1); canvas.drawBitmap(bitmap, point1.x, point1.y, paint); canvas.restore();canvas.save(); canvas.clipPath(path2); canvas.drawBitmap(bitmap, point2.x, point2.y, paint); canvas.restore();2 幾何變換
幾何變換的使用大概分為三類:
2.1 使用 Canvas 來做常見的二維變換:
2.1.1 Canvas.translate(float dx, float dy) 平移
參數里的?dx?和?dy?表示橫向和縱向的位移。
canvas.save(); canvas.translate(200, 0); canvas.drawBitmap(bitmap, x, y, paint); canvas.restore();好吧這個從截圖并不能看出什么,那你就用心去感受吧
2.1.2 Canvas.rotate(float degrees, float px, float py) 旋轉
參數里的?degrees?是旋轉角度,單位是度(也就是一周有 360° 的那個單位),方向是順時針為正向;?px?和?py?是軸心的位置。
canvas.save(); canvas.rotate(45, centerX, centerY); canvas.drawBitmap(bitmap, x, y, paint); canvas.restore();2.1.3 Canvas.scale(float sx, float sy, float px, float py) 放縮
參數里的?sx?sy?是橫向和縱向的放縮倍數;?px?py?是放縮的軸心。
canvas.save(); canvas.scale(1.3f, 1.3f, x + bitmapWidth / 2, y + bitmapHeight / 2); canvas.drawBitmap(bitmap, x, y, paint); canvas.restore();2.1.4 skew(float sx, float sy) 錯切
參數里的?sx?和?sy?是 x 方向和 y 方向的錯切系數。
canvas.save(); canvas.skew(0, 0.5f); canvas.drawBitmap(bitmap, x, y, paint); canvas.restore();2.2 使用 Matrix 來做變換
2.2.1 使用 Matrix 來做常見變換
Matrix?做常見變換的方式:
效果就不放圖了,和?Canvas?是一樣的。
把?Matrix?應用到?Canvas?有兩個方法:?Canvas.setMatrix(matrix)?和?Canvas.concat(matrix)。
2.2.2 使用 Matrix 來做自定義變換
Matrix?的自定義變換使用的是?setPolyToPoly()?方法。
2.2.2.1 Matrix.setPolyToPoly(float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount) 用點對點映射的方式設置變換
poly?就是「多」的意思。setPolyToPoly()?的作用是通過多點的映射的方式來直接設置變換。「多點映射」的意思就是把指定的點移動到給出的位置,從而發生形變。例如:(0, 0) -> (100, 100) 表示把 (0, 0) 位置的像素移動到 (100, 100) 的位置,這個是單點的映射,單點映射可以實現平移。而多點的映射,就可以讓繪制內容任意地扭曲。
Matrix matrix = new Matrix(); float pointsSrc = {left, top, right, top, left, bottom, right, bottom}; float pointsDst = {left - 10, top + 50, right + 120, top - 90, left + 20, bottom + 30, right + 20, bottom + 60};...matrix.reset(); matrix.setPolyToPoly(pointsSrc, 0, pointsDst, 0, 4);canvas.save(); canvas.concat(matrix); canvas.drawBitmap(bitmap, x, y, paint); canvas.restore();參數里,src?和?dst?是源點集合目標點集;srcIndex?和?dstIndex?是第一個點的偏移;pointCount是采集的點的個數(個數不能大于 4,因為大于 4 個點就無法計算變換了)。
2.3 使用 Camera 來做三維變換
Camera?的三維變換有三類:旋轉、平移、移動相機。
2.3.1 Camera.rotate*() 三維旋轉
Camera.rotate*()?一共有四個方法:?rotateX(deg)?rotateY(deg)?rotateZ(deg)rotate(x, y, z)。這四個方法的區別不用我說了吧?
canvas.save();camera.rotateX(30); // 旋轉 Camera 的三維空間 camera.applyToCanvas(canvas); // 把旋轉投影到 Canvascanvas.drawBitmap(bitmap, point1.x, point1.y, paint); canvas.restore();另外,Camera?和?Canvas?一樣也需要保存和恢復狀態才能正常繪制,不然在界面刷新之后繪制就會出現問題。所以上面這張圖完整的代碼應該是這樣的:
canvas.save();camera.save(); // 保存 Camera 的狀態 camera.rotateX(30); // 旋轉 Camera 的三維空間 camera.applyToCanvas(canvas); // 把旋轉投影到 Canvas camera.restore(); // 恢復 Camera 的狀態canvas.drawBitmap(bitmap, point1.x, point1.y, paint); canvas.restore();如果你需要圖形左右對稱,需要配合上?Canvas.translate(),在三維旋轉之前把繪制內容的中心點移動到原點,即旋轉的軸心,然后在三維旋轉后再把投影移動回來:
canvas.save();camera.save(); // 保存 Camera 的狀態 camera.rotateX(30); // 旋轉 Camera 的三維空間 canvas.translate(centerX, centerY); // 旋轉之后把投影移動回來 camera.applyToCanvas(canvas); // 把旋轉投影到 Canvas canvas.translate(-centerX, -centerY); // 旋轉之前把繪制內容移動到軸心(原點) camera.restore(); // 恢復 Camera 的狀態canvas.drawBitmap(bitmap, point1.x, point1.y, paint); canvas.restore();Canvas?的幾何變換順序是反的,所以要把移動到中心的代碼寫在下面,把從中心移動回來的代碼寫在上面。
2.3.2 Camera.translate(float x, float y, float z) 移動
它的使用方式和?Camera.rotate*()?相同,而且我在項目中沒有用過它,所以就不貼代碼和效果圖了。
2.3.3 Camera.setLocation(x, y, z) 設置虛擬相機的位置
注意!這個方法有點奇葩,它的參數的單位不是像素,而是 inch,英寸。
我 TM 的真沒逗你,我也沒有胡說八道,它的單位就。是。英。寸。
這種設計源自 Android 底層的圖像引擎?Skia?。在 Skia 中,Camera 的位置單位是英寸,英寸和像素的換算單位在 Skia 中被寫死為了 72 像素,而 Android 中把這個換算單位照搬了過來。是的,它。寫。死。了。
吐槽到此為止,俗話說看透不說透,還是好朋友。
在?Camera?中,相機的默認位置是 (0, 0, -8)(英寸)。8 x 72 = 576,所以它的默認位置是 (0, 0, -576)(像素)。
如果繪制的內容過大,當它翻轉起來的時候,就有可能出現圖像投影過大的「糊臉」效果。而且由于換算單位被寫死成了 72 像素,而不是和設備 dpi 相關的,所以在像素越大的手機上,這種「糊臉」效果會越明顯。
而使用?setLocation()?方法來把相機往后移動,就可以修復這種問題。
camera.setLocation(0, 0, newZ);Camera.setLocation(x, y, z)?的?x?和?y?參數一般不會改變,直接填 0 就好。
好了,上面這些就是本期的內容:范圍裁切和幾何變換。
練習項目
為了避免轉頭就忘,強烈建議你趁熱打鐵,做一下這個練習項目:HenCoderPracticeDraw4
下期預告
到這期為止,所有繪制的「術」就講完了,下期講的是「道」:繪制順序。
總結
以上是生活随笔為你收集整理的HenCoder Android 开发进阶:自定义 View 1-4 Canvas 对绘制的辅助 clipXXX() 和 Matrix的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Node mysql
- 下一篇: Android 检查版本更新 Ser