一悄谐、簡介
Android android.graphics.Matrix
類是一個3 x 3的矩陣(方陣)侦啸,上一張幾乎所有介紹Matrix的文章都會引用的Matrix內(nèi)容圖:
二、相關(guān)方法
1坠狡、equals
比較兩個矩陣是否相等继找。
Matrix matrix1 = new Matrix();
Matrix matrix2 = new Matrix();
matrix1.setTranslate(1,2);
matrix2.setTranslate(2,2);
// 輸出:matrix1 == matrix2:false
System.out.println("matrix1 == matrix2:" + matrix1.equals(matrix2));
2、+號相連/toString/toShortString
將矩陣轉(zhuǎn)換為字符串逃沿。
Matrix matrix = new Matrix();
// 輸出:+號相連:Matrix{[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]}
System.out.println("+號相連:" + matrix);
// 輸出:Matrix{[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]}
System.out.println("toString:" + matrix.toString());
// 輸出:[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]
System.out.println("toShortString:" + matrix.toShortString());
3婴渡、getValues()、setValues()
當(dāng)我們調(diào)用Matrix類的getValues(float[] values)凯亮、setValues(float[] values)
方法時边臼,可以將這個矩陣轉(zhuǎn)換成一個數(shù)組進(jìn)行操作。轉(zhuǎn)換后的數(shù)組為:
[ MSCALE_X, MSKEW_X, MTRANS_X, MSKEW_Y, MSCALE_Y, MTRANS_Y, MPERSP_0, MPERSP_1, MPERSP_2]
為了方便操作這個數(shù)組假消,在android.graphics.Matrix
類中柠并,定義了MSCALE_X、MSKEW_X...變量富拗,分別代表各自功能在數(shù)組中對應(yīng)的下標(biāo)臼予,具體內(nèi)容如下:
public static final int MSCALE_X = 0; //!< use with getValues/setValues
public static final int MSKEW_X = 1; //!< use with getValues/setValues
public static final int MTRANS_X = 2; //!< use with getValues/setValues
public static final int MSKEW_Y = 3; //!< use with getValues/setValues
public static final int MSCALE_Y = 4; //!< use with getValues/setValues
public static final int MTRANS_Y = 5; //!< use with getValues/setValues
public static final int MPERSP_0 = 6; //!< use with getValues/setValues
public static final int MPERSP_1 = 7; //!< use with getValues/setValues
public static final int MPERSP_2 = 8; //!< use with getValues/setValues
方法示例:
Matrix matrix = new Matrix();
// matrix = [1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]
System.out.println("matrix = " + matrix.toShortString());
float[] values = new float[9];
matrix.getValues(values);
// matrix轉(zhuǎn)換成數(shù)組后 = [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]
System.out.println("matrix轉(zhuǎn)換成數(shù)組后 = " + Arrays.toString(values));
// 為matrix賦值
values [Matrix.MTRANS_X] = 2;
values [Matrix.MTRANS_Y] = 3;
matrix.setValues(values);
// matrix = [1.0, 0.0, 2.0][0.0, 1.0, 3.0][0.0, 0.0, 1.0]
System.out.println("matrix = " + matrix.toShortString());
4、setXXX/preXXX/postXXX
XXX可以是Translate啃沪、Scale粘拾、Rotate、Skew和Concat创千。其中Concat參數(shù)為Matrix缰雇,表示直接操作Matrix入偷。由于縮放、旋轉(zhuǎn)械哟、錯切可以繞中心操作疏之,如果指定了中心,則變換步驟為:
- 將原點平移到該點暇咆。
- 做縮放锋爪、錯切、旋轉(zhuǎn)操作糯崎。
- 原點平移到原來的原點處几缭。
方法參數(shù)轉(zhuǎn)換成了一個怎樣的矩陣河泳?
// 下面代碼中參數(shù)(2,2) 轉(zhuǎn)換后的矩陣為
// [2.0, 0.0, 0.0]
// [0.0, 2.0, 0.0]
// [0.0, 0.0, 1.0]
// 即根據(jù)XXX代表的功能修改矩陣中對應(yīng)功能位置的值即可
matrix.postScale(2,2);
setXXX
首先會將該Matrix重置為單位矩陣沃呢,即相當(dāng)于首先會調(diào)用reset()方法,然后再設(shè)置該Matrix中對應(yīng)功能的值拆挥。例:
// [1.0, 0.0, 0.0]
// [0.0, 1.0, 0.0]
// [0.0, 0.0, 1.0]
Matrix matrix = new Matrix();
// [1.0, 0.0, 0.0] [2.0, 3.0, 4.0]
// [0.0, 1.0, 0.0] -> [2.0, 0.0, 0.0]
// [0.0, 0.0, 1.0] [1.0, 1.0, 1.0]
matrix.setValues(new float[]{2.0f,3.0f, 4.0f,
2.0f,0.0f, 0.0f,
1.0f,1.0f,1.0f});
// [2.0, 3.0, 4.0] [1.0, 0.0, 0.0] [2.0, 0.0, 0.0]
// [2.0, 2.0, 0.0] -> [0.0, 1.0, 0.0] -> [0.0, 2.0, 0.0]
// [1.0, 1.0, 1.0] [0.0, 0.0, 1.0] [0.0, 0.0, 1.0]
matrix.setScale(2,2);
preXXX
不會重置Matrix薄霜,相當(dāng)于當(dāng)前操作矩陣(A)左乘參數(shù)矩陣(B),即AB纸兔。例:
// [1.0, 0.0, 0.0]
// [0.0, 1.0, 0.0]
// [0.0, 0.0, 1.0]
Matrix matrix = new Matrix();
// [1.0, 0.0, 0.0] [2.0, 3.0, 4.0]
// [0.0, 1.0, 0.0] -> [2.0, 0.0, 0.0]
// [0.0, 0.0, 1.0] [1.0, 1.0, 1.0]
matrix.setValues(new float[]{2.0f,3.0f, 4.0f,
2.0f,0.0f, 0.0f,
1.0f,1.0f,1.0f});
// [2.0, 3.0, 4.0] [2.0, 0.0, 0.0] [4.0, 6.0, 4.0]
// [2.0, 0.0, 0.0](matrix) * [0.0, 2.0, 0.0] = [4.0, 0.0, 0.0](matrix)
// [1.0, 1.0, 1.0] [0.0, 0.0, 1.0] [2.0, 2.0, 1.0]
matrix.preScale(2,2);
postXXX
不會重置Matrix惰瓜,相當(dāng)于當(dāng)前操作矩陣(A)右乘參數(shù)矩陣(B),即BA汉矿,例:
// [1.0, 0.0, 0.0]
// [0.0, 1.0, 0.0]
// [0.0, 0.0, 1.0]
Matrix matrix = new Matrix();
// [1.0, 0.0, 0.0] [2.0, 3.0, 4.0]
// [0.0, 1.0, 0.0] -> [2.0, 0.0, 0.0]
// [0.0, 0.0, 1.0] [1.0, 1.0, 1.0]
matrix.setValues(new float[]{2.0f,3.0f, 4.0f,
2.0f,0.0f, 0.0f,
1.0f,1.0f,1.0f});
// [2.0, 0.0, 0.0] [2.0, 3.0, 4.0] [4.0, 6.0, 8.0]
// [0.0, 2.0, 0.0] * [2.0, 0.0, 0.0] (matrix) = [4.0, 0.0, 0.0](matrix)
// [0.0, 0.0, 1.0] [1.0, 1.0, 1.0] [1.0, 1.0, 1.0]
matrix.postScale(2,2);
setContact
關(guān)于setContact(Matrix m1,Matrix m2)方法崎坊,需要單獨說下,它的參數(shù)為兩個Matrix對象洲拇,計算規(guī)則為:當(dāng)前操作的Matrix對象 = m1 * m2;
例:
// [1.0, 0.0, 0.0]
// [0.0, 1.0, 0.0]
// [0.0, 0.0, 1.0]
Matrix matrix = new Matrix();
Matrix matrix1 = new Matrix();
Matrix matrix2 = new Matrix();
// [1.0, 0.0, 0.0] [2.0, 3.0, 4.0]
// [0.0, 1.0, 0.0] -> [2.0, 0.0, 0.0]
// [0.0, 0.0, 1.0] [1.0, 1.0, 1.0]
matrix1.setValues(new float[]{2.0f,3.0f, 4.0f,
2.0f,0.0f, 0.0f,
1.0f,1.0f,1.0f});
// [1.0, 0.0, 0.0] [2.0, 5.0, 4.0]
// [0.0, 1.0, 0.0] -> [3.0, 0.0, 0.0]
// [0.0, 0.0, 1.0] [1.0, 2.0, 1.0]
matrix2.setValues(new float[]{2.0f,5.0f, 4.0f,
3.0f,0.0f, 0.0f,
1.0f,2.0f,1.0f});
// [2.0, 3.0, 4.0] [2.0, 5.0, 4.0] [17.0, 18.0, 12.0]
// [2.0, 2.0, 0.0](matrix1) * [3.0, 0.0, 0.0](matrix2) = [4.0, 10.0, 8.0 ] (matrix)
// [1.0, 1.0, 1.0] [1.0, 2.0, 1.0] [6.0, 7.0, 5.0 ]
matrix.setConcat(matrix1,matrix2);
5奈揍、mapRadius/mapPoints/mapRect/mapVectors
可翻譯為將矩陣映射到(作用于)點、矩形赋续、半徑男翰、向量。
mapRadius
半徑的計算纽乱。例:
// 一個半徑為100.0f的圓蛾绎,放大1倍后,半徑也將增大一倍鸦列。據(jù)說用在畫布中的圓隨畫布大小變化時
float radius = 100.0f;
float radiusAfterMatrix;
Matrix matrixRadius = new Matrix();
matrixRadius.setScale(2,2);
radiusAfterMatrix = matrixRadius.mapRadius(radius);
// 輸出:radius=200.0
System.out.println("radius=" + radiusAfterMatrix);
mapPoints
此方法有3個重載方法租冠。點數(shù)組各值分別代表pts[x0,y0,x1,y1 ... xn,yn]
,因為一個點的確定需要x坐標(biāo)和y坐標(biāo)兩個值,所以薯嗤,pts數(shù)組的長度一般為偶數(shù)顽爹,如果為奇數(shù),則最后一個值不參與計算(長度為1將不計算)应民。下面給出具體例子话原,例子中將會詳細(xì)說明mapPoints方法夕吻。
// =======================
// mapPoints(float[] pts)
// =======================
// 運算后的結(jié)果會保存在pts數(shù)組中,原pts數(shù)組中的內(nèi)容會被覆蓋
// 1.《點的移動》,對于任意點(Xn,Yn),x軸方向平移dx,y軸方向平移dy后有:
// Xn = Xn + dx
// Yn = Yn + dy
float[] ptsTrans = {6,2};
Matrix matrixTrans = new Matrix();
matrixTrans.setTranslate(-2,2);
matrixTrans.mapPoints(ptsTrans);
// 輸出:trans=[4.0, 4.0]
System.out.println("trans=" + Arrays.toString(ptsTrans));
// 2.《點的放大》繁仁,對于任意點(Xn,Yn),繞點(px,py)x軸涉馅、y軸方向分別放大sx倍、sy倍后黄虱,有:
// Xn = Xn * sx + (px - px * sx)
// Yn = Yn * sy + (py - sy * py)
float[] ptsScale = {2,3};
Matrix matrixScale = new Matrix();
matrixScale.setScale(3,6,2,2);
matrixScale.mapPoints(ptsScale);
// 輸出:scale=[2.0, 8.0]
System.out.println("scale=" + Arrays.toString(ptsScale));
// 3.《點的旋轉(zhuǎn)》稚矿,對于任意點(Xn,Yn),繞點(px,py)旋轉(zhuǎn)a度后,有:
// Xn = (Xn - px) * cos(a) - (Yn - py) * sin(a) + px
// Yn = (Xn - px) * sin(a) + (Yn - py) * cos(a) + py
float[] ptsRotate = {6,6};
Matrix matrixRotate = new Matrix();
matrixRotate.preRotate(90,2,3);
matrixRotate.mapPoints(ptsRotate);
// 輸出:rotate=[-1.0,7.0]
System.out.println("rotate=" + Arrays.toString(ptsRotate));
// 4.《點的錯切》,對于任意點(Xn,Yn),繞點(px,py)x軸捻浦、y軸方向分別錯切kx晤揣、ky后,有:
// Xn = Xn + kx(Yn - py)
// Yn = Yn + ky(Xn - px)
float[] ptsSkew = {3,2};
Matrix matrixSkew = new Matrix();
matrixSkew.setSkew(2,3,6,8);
matrixSkew.mapPoints(ptsSkew);
// 輸出:skew=[-9.0,-7.0]
System.out.println("skew=" + Arrays.toString(ptsSkew));
// ===================================
// mapPoints(float[] dst, float[] src)
// ===================================
// 運算后的結(jié)果保存在dst數(shù)組中朱灿,原src數(shù)組中的內(nèi)容會保留
float[] src = {2,3,3,3};
float[] dst = new float[src.length];
Matrix matrixDstSrc = new Matrix();
matrixDstSrc.setTranslate(2,3);
matrixDstSrc.mapPoints(dst,src);
// 輸出:dst=[4.0,6.0,5.0,6.0]
System.out.println("dst=" + Arrays.toString(dst));
// 輸出:src=[2.0,3.0,3.0,3.0]
System.out.println("src=" + Arrays.toString(src));
// ==============================================================================
// mapPoints(float[] dst, ---- 計算結(jié)果存放數(shù)組
// int dstIndex, ---- dst數(shù)組存放計算結(jié)果時起始下標(biāo)
// float[] src, ---- 計算的源數(shù)組
// int srcIndex, ---- 源數(shù)組計算時起始下標(biāo)
// int pointCount ---- 從起始下標(biāo)開始一共要計算多少個點
// )
// ==============================================================================
// 運算后的結(jié)果保存在dst數(shù)組中
float[] src1 = {2,3,3,3,2,3};
float[] dst1 = new float[]{6,6,6,6,6,6};
Matrix matrixDstSrc1 = new Matrix();
matrixDstSrc1.setTranslate(1,1);
// 1)從src1下標(biāo)為2的位置開始計算昧识,計算1個點,注意盗扒,是一個點跪楞,不是一個長度;計算的結(jié)果只保存計算的點侣灶,未計算的點將舍棄甸祭,即結(jié)果為:[4.0,4.0]
// 2)將src1計算后的結(jié)果,從dst1下標(biāo)為2的位置開始放置
// 注意褥影,從存放數(shù)組開始的位置存放計算結(jié)果時池户,如果長度不夠,將拋出 ArrayIndexOutOfBoundsException 異常
matrixDstSrc1.mapPoints(dst1,5,src1,2,1);
// 輸出:dst=[0.0,0.0,2.0,3.0,4.0,4.0]
System.out.println("dst1=" + Arrays.toString(dst1));
// 輸出:src=[2.0,3.0,3.0,3.0,2.0,3.0]
System.out.println("src1=" + Arrays.toString(src1));
mapRect
將矩形的4個點按Matrix中設(shè)定的值變換凡怎,返回值為變換后是否還為一個矩形校焦。此方法有2個重載方法。
// ============================================
// mapRect(RectF rect)
// ============================================
// 結(jié)果存放在rect中栅贴,原rect將被覆蓋
RectF rectF = new RectF(100,100,200,200);
// 輸出:rectFbefore = RectF(100.0, 100.0, 200.0, 200.0)
System.out.println("rectFbefore = " + rectF);
Matrix matrixRectF = new Matrix();
matrixRectF.setScale(2,2);
matrixRectF.mapRect(rectF);
// 輸出:rectFafter = RectF(200.0, 200.0, 400.0, 400.0)
System.out.println("rectFafter = " + rectF);
// ============================================
// mapRect(RectF dst,RectF src)
// ============================================
// 結(jié)果存放在dst中斟湃,原src會保留。其它與mapRect(RectF rect)方法相同
mapVectors
用法和mapPoints方法類似檐薯,此方法有3個重載方法凝赛,唯一不同的是mapVectors不受位移影響。例:
float[] vector = {2,3};
float[] point = {2,3};
Matrix matrixTranslate = new Matrix();
matrixTranslate.setTranslate(2,3);
matrixTranslate.mapVectors(vector);
matrixTranslate.mapPoints(point);
// 輸出:vector = [2.0,3.0]
System.out.println("vector = " + Arrays.toString(vector));
// 輸出:point = [4.0,6.0]
System.out.println("point = " + Arrays.toString(point));
6坛缕、invert
做相反的運算墓猎。得到變化前的狀態(tài)。例:圖形旋轉(zhuǎn)一定角度后再恢復(fù)旋轉(zhuǎn)前的狀態(tài)赚楚。matrixOri.invert(matrixInvert)
方法可翻譯為:將matrixOri
這個矩陣反轉(zhuǎn)后存放在matrixInvert
這個矩陣中毙沾, matrixInvert
這個矩陣中原來的值將被覆蓋。
// ==========================================
// 移動
// ==========================================
// [1.0, 0.0, Δx] [1.0, 0.0, -Δx]
// [0.0, 1.0, Δy] invert -> [0.0, 1.0, -Δy]
// [0.0, 0.0, 1.0] [0.0, 0.0, 1.0]
Matrix matrixTrans = new Matrix();
matrixTrans.setTranslate(2,3);
// [1.0, 0.0, 2.0]
// [0.0, 1.0, 3.0]
// [0.0, 0.0, 1.0]
System.out.println("matrixTrans = " + matrixTrans);
matrixTrans.invert(matrixTrans);
// [1.0, 0.0, -2.0]
// [0.0, 1.0, -3.0]
// [0.0, 0.0, 1.0]
System.out.println("matrixTrans = " + matrixTrans);
// ==========================================
// 縮放
// ==========================================
// [sx, 0, -px] [1/sx, 0, px/2]
// [0, sy, -py] invert -> [0, 1/sy, py/2]
// [0.0, 0.0, 1.0] [0.0, 0.0, 1.0]
Matrix matrixScale = new Matrix();
matrixScale.setScale(2,2,12,7);
// [2.0, 0.0, -12.0]
// [0.0, 2.0, -7.0]
// [0.0, 0.0, 1.0]
System.out.println("matrixScale = " + matrixScale);
matrixScale.invert(matrixScale);
// [0.5, 0.0, 6.0]
// [0.0, 0.5, 3.5]
// [0.0, 0.0, 1.0]
System.out.println("matrixScale = " + matrixScale);
7宠页、isIdentity
判斷一個矩陣是否為單位矩陣
Matrix matrix = new Matrix();
// 輸出:matrix is identity:true
System.out.println("matrix is identity:" + matrix.isIdentity());
matrix.setTranslate(1,2);
// 輸出:matrix is identity:false
System.out.println("matrix is identity:" + matrix.isIdentity());
8左胞、setPolyToPoly
根據(jù)src坐標(biāo)到dst坐標(biāo)的變換關(guān)系寇仓,生成對應(yīng)的Matrix矩陣。
// ==================================================================================================
// setPolyToPoly(float[] src, 變換前的點數(shù)組烤宙,內(nèi)容為[x0, y0, x1, y1, ...]
// int srcIndex, 第一個變化的點在src數(shù)組中的下標(biāo)
// float[] dst, src變換后的點數(shù)組遍烦,內(nèi)容為[x0‘, y0’, x1’, y1’, ...],與src數(shù)組一一對應(yīng)
// int dstIndex, 變化后的第一個點在dst數(shù)組中存儲的位置
// int pointCount 一次一共需要變換多少個點躺枕,取值范圍[0,4]
// )
// ==================================================================================================
float[] src = {1,2};
float[] dst = {2,4};
// [1.0, 0.0, 0.0]
// matrix = [0.0, 1.0, 0.0]
// [0.0, 0.0, 1.0]
Matrix matrix = new Matrix();
System.out.println("matrix = " + matrix.toShortString());
matrix.setPolyToPoly(src,0,dst,0,1);
// [1.0, 0.0, 1.0]
// matrix = [0.0, 1.0, 2.0]
// [0.0, 0.0, 1.0]
System.out.println("matrix = " + matrix.toShortString());
// 驗證這個生成的matrix是否正確
// [1.0, 0.0, 1.0] [1] [2.0]
// [0.0, 1.0, 2.0] * [2] = [4.0]
// [0.0, 0.0, 1.0] [1] [1.0]
9服猪、setRectToRect
將矩形填充到矩形中。其中在填充時可以指定4種填充模式拐云,這4種模式用Matrix.ScaleToFit
枚舉類型表示罢猪,關(guān)于這4種填充模式,借用一張官方demo圖:
Matrix matrix = new Matrix();
RectF rectFSrc = new RectF(100,100,200,400);
RectF rectFDst = new RectF(100,100,400,200);
matrix.setRectToRect(rectFSrc,rectFDst, Matrix.ScaleToFit.FILL);
三叉瘩、總結(jié)
Matrix可以運用到很多地方膳帕,但基本的原理都是通過Matrix提供的API對Matrix中值的更改,然后再將這個Matrix作用于不同的對象(圖片房揭、畫布等)备闲。
本篇文章主要是對android.graphics.Matrix
類中常用方法的講解,與網(wǎng)上其它講解Matrix的文章方向可能有所不同捅暴。由于文章很多細(xì)致的講解都在代碼的注釋中,請各位一定要關(guān)注文章中的代碼示例咧纠。文章中的代碼示例均可復(fù)制>>粘貼>>運行蓬痒,可自行測試。
由于本人功力有限漆羔,文章中可能會有出錯的地方梧奢。如果各位發(fā)現(xiàn)有誤的地方請指證。當(dāng)然演痒,如果有什么地方不理解亲轨,也可以提出來。