深入理解 Android 中的 Matrix

2021-08-19 12:39:29 字數 3675 閱讀 5833

在 android 開發中,矩陣是乙個功能強大並且應用廣泛的神器,例如:用它來製作動畫效果、改變大小、給加各類濾鏡等。對於矩陣,android 官方 sdk 為我們提供了乙個強大的類 matrix (還有 colormatrix )是一直困擾著我的問題,雖然大致能夠呼叫相應的 api ,但卻一直 get 不到其內在的梗。但是出來混總是別想著蒙混過關的,所以最近重新操起一年畢業的線性代數,再本著小事問老婆,大事問google的心態,終於把多年不解的問題給破了。出於好記性不如爛筆頭的原因,便有了本文。在此先感謝下面兩篇令我茅舍頓開的文章:

matrix 是 android sdk 提供的乙個矩陣類,它代表乙個 3 x 3 的矩陣(不懂矩陣為何物的童鞋就要自行 google 了)。 matrix 提供了讓我們獲得 matrix 值的 api ——getvalues

利用此 api 傳入乙個長度為 9 的 float 陣列,即可獲得矩陣中每個元素的值。那麼這 9 個浮點數的作用和意義是什麼呢,從 android 官方文件上看,它為這個陣列中的每乙個元素都定義了乙個下標常量

這個 9 個常量取值分別是 0 - 8

如果我們將這個 float 排成直觀的矩陣格式,那它將是下面這樣子的

實際上我們平常利用 matrix 來進行 translate(平移)、scale(縮放)、rotate(旋轉)的操作,就是在操作著這個矩陣中元素的數值來達到我們想要的效果。但是現在問題來了,上面提到的平移、縮放、旋轉操作中,旋轉和縮放可以用乘法表示,而平移就只能用加法表示,而且 matrix 是乙個 3 x 3 的矩陣,實際上表示這些操作 2 x 2 的矩陣足矣!

如上,可以依次看到平移、縮放、旋轉的矩陣,其中

至於上面矩陣的推導過程,網路上很多,這裡就不去贅述了。以前到了這裡,我就會很納悶,為什麼 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 操作也是一樣,感興趣的童鞋可以自行**驗證一番。

按照第一小節裡面通過齊次座標轉換而來的矩陣方程可以知道,假設一根線執行了平移操作,相當於線上每個點的座標被下方的矩陣左乘。(縮放和旋轉操作也是同理)

如果要進行同時縮放、平移之類的符合變化操作,也無非就是選取相應的矩陣做左乘操作。為了加深矩陣變換對應 matrix api 呼叫的理解,直接通過下面的乙個自定義的動畫效果和**來講解好了。

public

class

******customanimation

extends

animation

@override

protected

void

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);}}

實際上這幾行**用矩陣來表示就相當於如下所示:

關於**的作用上邊已經給出了注釋,這裡就不多寫了。主要還是要弄明白 matrix 復合變換中 pre 、 post 等操作與其對應的矩陣發生的左乘、右乘變化。

到此,整篇文章已經完結,相信已經能夠讓你明白開頭提到的三個問題。其實我們也可以發現,google 封裝了 matrix 已經是很完美了,幾乎遮蔽了所有的數學細節,使得我這種數學水平一般的開發者也能夠去呼叫相應的 api 實現一些簡單的效果。雖然被封裝得很完美,但掌握相應的一些原理,依舊可以幫你更好的理解一些技術實現,此次加深了對 matrix 一些操作的理解,幫我自己解決了以前不少的困惑,不知道有沒有幫你 get 到一些什麼呢?

上面給的示例**很簡單,複製黏貼即可執行玩耍,實在需要直接執行原始碼的童鞋就到 找吧!

2016 年 9 月 23-24 日,由 csdn 和創新工場聯合主辦的「mdcc 2016 移動開發者大會• 中國」(mobile developer conference china)將在北京• 國家會議中心召開,來自ios、android、跨平台開發、產品設計、vr開發、移動直播、人工智慧、物聯網、硬體開發、資訊無障礙10個領域的技術專家將分享他們在各自行業的真知灼見。

從即日起至8月7日23:59,mdcc 2016移動開發者大會門票5折優惠。五人以上**更有特惠,限量**,預購從速。(票務詳情鏈結)

《深入理解Android》一導讀

第1章 搭建源 編譯環境 1.1 android全原始碼開發環境 1.2 android常用工具使用及相關技巧說明 1.3 webkit源 目錄結構 1.4 webkit 除錯 1.5 本章小結 第2章 瀏覽器工作原理及webkit概覽 2.1 瀏覽器工作原理概述 2.2 瀏覽器和webkit簡史 ...

深入理解C語言 深入理解指標

關於指標,其是c語言的重點,c語言學的好壞,其實就是指標學的好壞。其實指標並不複雜,學習指標,要正確的理解指標。指標也是一種變數,占有記憶體空間,用來儲存記憶體位址 指標就是告訴編譯器,開闢4個位元組的儲存空間 32位系統 無論是幾級指標都是一樣的 p操作記憶體 在指標宣告時,號表示所宣告的變數為指...

mysql 索引深入理解 深入理解MySql的索引

為什麼索引能提高查詢速度 先從 mysql的基本儲存結構說起 mysql的基本儲存結構是頁 記錄都存在頁裡邊 各個資料頁可以組成乙個雙向鍊錶每個資料頁中的記錄又可以組成乙個單向鍊錶 每個資料頁都會為儲存在它裡邊兒的記錄生成乙個頁目錄,在通過主鍵查詢某條記錄的時候可以在頁目錄中使用二分法快速定位到對應...