原文連接:http://geek.csdn.net/news/detail/89873git
做者:D_clockgithub
在 Android 開發中,矩陣是一個功能強大而且應用普遍的神器,例如:用它來製做動畫效果、改變圖片大小、給圖片加各種濾鏡等。對於矩陣,Android 官方 SDK 爲咱們提供了一個強大的類 Matrix (還有 ColorMatrix )是一直困擾着個人問題,雖然大體可以調用相應的 API ,但卻一直 get 不到其內在的梗。可是出來混老是別想着矇混過關的,因此最近從新操起一年畢業的線性代數,再本着小事問老婆,大事問Google的心態,終於把多年不解的問題給破了。出於好記性不如爛筆頭的緣由,便有了本文。在此先感謝下面兩篇令我茅舍頓開的文章:數組
讀完本文,相信你可以搞明白如下三個問題:網絡
Matrix 是 Android SDK 提供的一個矩陣類,它表明一個 3 X 3 的矩陣(不懂矩陣爲什麼物的童鞋就要自行 Google 了)。 Matrix 提供了讓咱們得到 Matrix 值的 API —— getValuesapp
利用此 API 傳入一個長度爲 9 的 float 數組,便可得到矩陣中每一個元素的值。那麼這 9 個浮點數的做用和意義是什麼呢,從 Android 官方文檔上看,它爲這個數組中的每個元素都定義了一個下標常量ide
這個 9 個常量取值分別是 0 - 8wordpress
若是咱們將這個 float 排成直觀的矩陣格式,那它將是下面這樣子的函數
實際上咱們日常利用 Matrix 來進行 Translate(平移)、Scale(縮放)、Rotate(旋轉)的操做,就是在操做着這個矩陣中元素的數值來達到咱們想要的效果。可是如今問題來了,上面提到的平移、縮放、旋轉操做中,旋轉和縮放能夠用乘法表示,而平移就只能用加法表示,並且 Matrix 是一個 3 X 3 的矩陣,實際上表示這些操做 2 X 2 的矩陣足矣!post
如上,能夠依次看到平移、縮放、旋轉的矩陣,其中動畫
至於上面矩陣的推導過程,網絡上不少,這裏就不去贅述了。之前到了這裏,我就會很納悶,爲何 2 X 2 矩陣能幹的事情,恰恰要用 3 X 3 矩陣去作,直到遇到前面提到的兩篇文章纔有所領悟。
其實在計算機圖形應用涉及到幾何變換,主要包括平移、旋轉、縮放。以矩陣表達式來計算這些變換時,平移是矩陣相加,旋轉和縮放則是矩陣相乘。那些數學大神們爲了方便計算,因此引入了同樣神器叫作齊次座標(不懂的童鞋,老規矩自行搜索),將平移的加法合併用乘法表示。因此,2 X 2 的矩陣通過一番變換後,成了下面這樣的。
至此,咱們能夠得知爲何 Matrix 是一個 3 X 3 的矩陣,其實 2 X 2 的矩陣是足以表示的,不過是爲了方便計算而合併寫成了 3 X 3 的格式。
一個 Matrix 共有 9 個元素,那麼它每一個元素的值發生改變會起到什麼做用呢?按照前面所示的齊次座標轉換獲得 3 X 3 的矩陣和 Android 文檔提供的官方結構相對應,咱們不難看出下面的對應關係(其實從 Matrix 中每一個位置的常量命名也能夠看出來):
從這咱們能夠看出這個 Matrix 結構中的每一個參數發揮着以下做用:
若是要進行代碼驗證的話,也很是簡單,例如直接只對 Matrix 作 Translate 的 API 調用操做,再將 Matrix 的信息打印到控制檯,你會發現整個 Matrix 確實只有 MTRANS_X、MTRANS_Y 兩個位置的數字在發生變化。其餘 Scale、Rotate、Skew 操做也是同樣,感興趣的童鞋能夠自行代碼驗證一番。
至此,咱們能夠大體弄清矩陣每一個元素的做用。至於 MPERSP_0、MPERSP_一、MPERSP_2 這三個參數,目前暫時不得而知,網上有文章說這三個參數控制着透視變換,可是文檔和 API 上都沒怎麼說起,因此仍是有待驗證研究的,有明白的童鞋不妨留言賜教一下,不勝感激。
按照第一小節裏面經過齊次座標轉換而來的矩陣方程能夠知道,假設一根線執行了平移操做,至關於線上每一個點的座標被下方的矩陣左乘。(縮放和旋轉操做也是同理)
若是要進行同時縮放、平移之類的符合變化操做,也無非就是選取相應的矩陣作左乘操做。爲了加深矩陣變換對應 Matrix API 調用的理解,直接經過下面的一個自定義的動畫效果和代碼來說解好了。
public class SimpleCustomAnimation extends Animation { private int mWidth, mHeight; @Override public void initialize(int width, int height, int parentWidth, int parentHeight) { super.initialize(width, height, parentWidth, parentHeight); this.mWidth = width; this.mHeight = height; } @Override protected void applyTransformation(float interpolatedTime, Transformation t) { Matrix matrix = t.getMatrix(); matrix.preScale(interpolatedTime, interpolatedTime);//縮放 matrix.preRotate(interpolatedTime * 360);//旋轉 //下面的Translate組合是爲了將縮放和旋轉的基點移動到整個View的中心,否則系統默認是以View的左上角做爲基點 matrix.preTranslate(-mWidth / 2, -mHeight / 2); matrix.postTranslate(mWidth / 2, mHeight / 2); } }
熟悉動畫這塊的童鞋確定知道,Animation 就是經過不斷改變 applyTransformation 函數傳入的 Matrix 來實現各類各樣的動畫效果的,經過上面 applyTransformation 寥寥的幾行 Matrix 的複合變換操做能夠獲得以下效果
實際上這幾行代碼用矩陣來表示就至關於以下所示:
關於代碼的做用上邊已經給出了註釋,這裏就很少寫了。主要仍是要弄明白 Matrix 複合變換中 pre 、 post 等操做與其對應的矩陣發生的左乘、右乘變化。
到此,整篇文章已經完結,相信已經可以讓你明白開頭提到的三個問題。其實咱們也能夠發現,Google 封裝了 Matrix 已是很完美了,幾乎屏蔽了全部的數學細節,使得我這種數學水平通常的開發者也可以去調用相應的 API 實現一些簡單的效果。雖然被封裝得很完美,但掌握相應的一些原理,依舊能夠幫你更好的理解一些技術實現,這次加深了對 Matrix 一些操做的理解,幫我本身解決了之前很多的困惑,不知道有沒有幫你 get 到一些什麼呢?
上面給的示例代碼很簡單,複製黏貼便可運行玩耍,實在須要直接運行源碼的童鞋就到 https://github.com/D-clock/AndroidStudyCode 找吧!