系列文章之 Android中自定義View(一)
系列文章之 Android中自定義View(二)
系列文章之 Android中自定義View(三)
系列文章之 Android中自定義View(四)
系列文章之 Android中自定義View(xml繪圖)
本文出自:
http://www.reibang.com/u/a1251e598483
我們?cè)谑褂酶鞣NApp時(shí)都會(huì)看到好多漂亮的效果,說(shuō)實(shí)話有的效果真的很好看,所以覺(jué)得能寫出這些效果的人都好厲害的說(shuō),自定義View 在Android 進(jìn)階相關(guān)的圖書(shū)中都是必會(huì)內(nèi)容,我也一直看過(guò)大概的自定義View 的內(nèi)容,看過(guò)之后還是覺(jué)得不夠詳細(xì),上手還是抓瞎. 剛好網(wǎng)上 扔物線 大神 寫了一個(gè)自定義view 的詳細(xì)教程. http://hencoder.com .如果想學(xué)習(xí)自定義View的同學(xué)請(qǐng)去 大神那里圍觀,本文是記錄自己學(xué)習(xí) 自定義View 的理解和收獲,也是一個(gè)記錄吧,等到用的時(shí)候比較容易找到.
我是分割線,下面開(kāi)始本文內(nèi)容--------------------------
自定義View分為以下幾個(gè)部分
- Canvas 的 drawXXX() 系列方法及 Paint 最常見(jiàn)的使用
- Paint 的完全攻略
- Canvas 對(duì)繪制的輔助——范圍裁切和幾何變換度宦。
- 使用不同的繪制方法來(lái)控制繪制順序
今天這篇就是第四部分: Canvas 對(duì)繪制的輔助 clipXXX() 和 Matrix
1 范圍裁切
范圍裁切有兩個(gè)方法: clipRect() 和 clipPath()。裁切方法之后的繪制代碼似枕,都會(huì)被限制在裁切范圍內(nèi)。
1.1 clipRect()
使用很簡(jiǎn)單年柠,直接應(yīng)用:
canvas.clipRect(left, top, right, bottom);
canvas.drawBitmap(bitmap, x, y, paint);
記得要加上 Canvas.save() 和 Canvas.restore() 來(lái)及時(shí)恢復(fù)繪制范圍菠净,所以完整代碼是這樣的:
canvas.save();
canvas.clipRect(left, top, right, bottom);
canvas.drawBitmap(bitmap, x, y, paint);
canvas.restore();
1.2 clipPath()
其實(shí)和 clipRect() 用法完全一樣,只是把參數(shù)換成了 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 來(lái)做常見(jiàn)的二維變換毅往;
使用 Matrix 來(lái)做常見(jiàn)和不常見(jiàn)的二維變換;
使用 Camera 來(lái)做三維變換派近。
2.1 使用 Canvas 來(lái)做常見(jiàn)的二維變換:
2.1.1 Canvas.translate(float dx, float dy) 平移
參數(shù)里的 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) 旋轉(zhuǎn)
參數(shù)里的 degrees 是旋轉(zhuǎn)角度,單位是度(也就是一周有 360° 的那個(gè)單位)渴丸,方向是順時(shí)針為正向侯嘀; 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) 放縮
參數(shù)里的 sx sy是橫向和縱向的放縮倍數(shù)谱轨; 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) 錯(cuò)切
參數(shù)里的 sx和 sy是 x 方向和 y 方向的錯(cuò)切系數(shù)。
canvas.save();
canvas.skew(0, 0.5f);
canvas.drawBitmap(bitmap, x, y, paint);
canvas.restore();
2.2 使用 Matrix 來(lái)做變換
2.2.1 使用 Matrix 來(lái)做常見(jiàn)變換
Matrix 做常見(jiàn)變換的方式:
創(chuàng)建 Matrix 對(duì)象土童;
調(diào)用 Matrix 的 pre/postTranslate/Rotate/Scale/Skew() 方法來(lái)設(shè)置幾何變換诗茎;
使用 Canvas.setMatrix(matrix) 或 Canvas.concat(matrix) 來(lái)把幾何變換應(yīng)用到 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 應(yīng)用到 Canvas 有兩個(gè)方法: Canvas.setMatrix(matrix) 和 Canvas.concat(matrix)献汗。
- Canvas.setMatrix(matrix):用 Matrix 直接替換 Canvas 當(dāng)前的變換矩陣敢订,即拋棄 Canvas 當(dāng)前的變換,改用 Matrix 的變換(不同的系統(tǒng)中 setMatrix(matrix) 的行為可能不一致罢吃,所以還是盡量用 concat(matrix) 吧)楚午;
- Canvas.concat(matrix):用 Canvas 當(dāng)前的變換矩陣和 Matrix 相乘,即基于 Canvas 當(dāng)前的變換尿招,疊加上 Matrix 中的變換矾柜。
2.2.2 使用 Matrix 來(lái)做自定義變換
Matrix 的自定義變換使用的是 setPolyToPoly() 方法阱驾。
2.2.2.1 Matrix.setPolyToPoly(float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount) 用點(diǎn)對(duì)點(diǎn)映射的方式設(shè)置變換
poly 就是「多」的意思。setPolyToPoly() 的作用是通過(guò)多點(diǎn)的映射的方式來(lái)直接設(shè)置變換怪蔑“∫祝「多點(diǎn)映射」的意思就是把指定的點(diǎn)移動(dòng)到給出的位置,從而發(fā)生形變饮睬。例如:(0, 0) -> (100, 100) 表示把 (0, 0) 位置的像素移動(dòng)到 (100, 100) 的位置租谈,這個(gè)是單點(diǎn)的映射,單點(diǎn)映射可以實(shí)現(xiàn)平移捆愁。而多點(diǎn)的映射割去,就可以讓繪制內(nèi)容任意地扭曲。
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();
參數(shù)里昼丑,
src和 dst 是源點(diǎn)集合目標(biāo)點(diǎn)集呻逆;
srcIndex和 dstIndex是第一個(gè)點(diǎn)的偏移;
pointCount是采集的點(diǎn)的個(gè)數(shù)(個(gè)數(shù)不能大于 4菩帝,因?yàn)榇笥?4 個(gè)點(diǎn)就無(wú)法計(jì)算變換了)咖城。
2.3 使用 Camera 來(lái)做三維變換
Camera 的三維變換有三類:旋轉(zhuǎn)、平移呼奢、移動(dòng)相機(jī)宜雀。
2.3.1 Camera.rotate*() 三維旋轉(zhuǎn)
Camera.rotate*() 一共有四個(gè)方法: rotateX(deg) rotateY(deg) rotateZ(deg) rotate(x, y, z)
canvas.save();camera.save(); // 保存 Camera 的狀態(tài)
camera.rotateX(30); // 旋轉(zhuǎn) Camera 的三維空間
canvas.translate(centerX, centerY); // 旋轉(zhuǎn)之后把投影移動(dòng)回來(lái) camera.applyToCanvas(canvas); // 把旋轉(zhuǎn)投影到
Canvas canvas.translate(-centerX, -centerY); // 旋轉(zhuǎn)之前把繪制內(nèi)容移動(dòng)到軸心(原點(diǎn))
camera.restore(); // 恢復(fù) Camera 的狀態(tài)
canvas.drawBitmap(bitmap, point1.x, point1.y, paint);
canvas.restore();
Canvas
的幾何變換順序是反的,所以要把移動(dòng)到中心的代碼寫在下面握础,把從中心移動(dòng)回來(lái)的代碼寫在上面辐董。
2.3.2 Camera.translate(float x, float y, float z) 移動(dòng)
它的使用方式和 Camera.rotate*() 相同,而且我在項(xiàng)目中沒(méi)有用過(guò)它禀综,所以就不貼代碼和效果圖了简烘。
2.3.3 Camera.setLocation(x, y, z) 設(shè)置虛擬相機(jī)的位置
注意!這個(gè)方法有點(diǎn)奇葩定枷,它的參數(shù)的單位不是像素孤澎,而是 inch,英寸欠窒。
在 Camera 中覆旭,相機(jī)的默認(rèn)位置是 (0, 0, -8)(英寸)。8 x 72 = 576贱迟,所以它的默認(rèn)位置是 (0, 0, -576)(像素)姐扮。
如果繪制的內(nèi)容過(guò)大絮供,當(dāng)它翻轉(zhuǎn)起來(lái)的時(shí)候衣吠,就有可能出現(xiàn)圖像投影過(guò)大的「糊臉」效果。而且由于換算單位被寫死成了 72 像素壤靶,而不是和設(shè)備 dpi 相關(guān)的缚俏,所以在像素越大的手機(jī)上,這種「糊臉」效果會(huì)越明顯。
而使用 setLocation() 方法來(lái)把相機(jī)往后移動(dòng)忧换,就可以修復(fù)這種問(wèn)題恬惯。
camera.setLocation(0, 0, newZ);
Camera.setLocation(x, y, z) 的 x 和 y 參數(shù)一般不會(huì)改變,直接填 0 就好亚茬。