系列文章之 Android中自定義View(一)
系列文章之 Android中自定義View(二)
系列文章之 Android中自定義View(三)
系列文章之 Android中自定義View(四)
系列文章之 Android中自定義View(xml繪圖)
本文出自:
http://www.lxweimin.com/u/a1251e598483
我們在使用各種App時都會看到好多漂亮的效果,說實話有的效果真的很好看,所以覺得能寫出這些效果的人都好厲害的說,自定義View 在Android 進階相關的圖書中都是必會內容,我也一直看過大概的自定義View 的內容,看過之后還是覺得不夠詳細,上手還是抓瞎. 剛好網上 扔物線 大神 寫了一個自定義view 的詳細教程. http://hencoder.com .如果想學習自定義View的同學請去 大神那里圍觀,本文是記錄自己學習 自定義View 的理解和收獲,也是一個記錄吧,等到用的時候比較容易找到.
我是分割線,下面開始本文內容--------------------------
自定義View分為以下幾個部分
- Canvas 的 drawXXX() 系列方法及 Paint 最常見的使用
- Paint 的完全攻略
- Canvas 對繪制的輔助——范圍裁切和幾何變換。
- 使用不同的繪制方法來控制繪制順序
今天這篇就是第四部分: Canvas 對繪制的輔助 clipXXX() 和 Matrix
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 幾何變換
幾何變換的使用大概分為三類:
使用 Canvas 來做常見的二維變換;
使用 Matrix 來做常見和不常見的二維變換;
使用 Camera 來做三維變換。
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 做常見變換的方式:
創建 Matrix 對象;
調用 Matrix 的 pre/postTranslate/Rotate/Scale/Skew() 方法來設置幾何變換;
使用 Canvas.setMatrix(matrix) 或 Canvas.concat(matrix) 來把幾何變換應用到 Canvas。
Matrix matrix = new Matrix();
...
matrix.reset();
matrix.postTranslate();
matrix.postRotate();
canvas.save();
canvas.concat(matrix);
canvas.drawBitmap(bitmap, x, y, paint);
canvas.restore();
把 Matrix 應用到 Canvas 有兩個方法: Canvas.setMatrix(matrix) 和 Canvas.concat(matrix)。
- Canvas.setMatrix(matrix):用 Matrix 直接替換 Canvas 當前的變換矩陣,即拋棄 Canvas 當前的變換,改用 Matrix 的變換(不同的系統中 setMatrix(matrix) 的行為可能不一致,所以還是盡量用 concat(matrix) 吧);
- Canvas.concat(matrix):用 Canvas 當前的變換矩陣和 Matrix 相乘,即基于 Canvas 當前的變換,疊加上 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.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,英寸。
在 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 就好。