編輯:關於Android編程
這裡我們會詳細講解matrix的各個方法,以及它的用法。matrix叫做矩陣,在前面講解 ColorFilter 的文章中,我們講解了ColorMatrix,他是一個4*5的矩陣。而這裡,我們講解的Matrix不是用於處理顏色的,而是處理圖形的。他是一個3*3的矩陣。
先看看matrix的矩陣是什麼樣子的:
這裡可以查看Matrix的代碼得到。那麼這個矩陣分別代表了什麼呢,這裡通過他們的名字可以看出,scale是縮放,skew是錯切(canvas變換中有講過),trans是平移,persp代表透視(官方文檔中,也沒有詳細講解,透視在這裡只做簡單介紹)。這裡需要把矩陣根據他們的作用劃分為4塊:
如上圖所示,這四塊區域各有作用。後面會詳細講解各個作用,先來看看這個矩陣是如何影響圖像的。先看看屏幕的坐標系:<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPjxpbWcgYWx0PQ=="這裡寫圖片描述" src="/uploadfile/Collfiles/20160519/20160519092735209.png" title="\" />
看上圖,這裡表示了屏幕的坐標系,其中的x,y軸是大家所熟知的,但是其實,一個物體他是存在於一個三維空間的,所以必然會有z軸。我們的屏幕,就像是一個窗口,透過它,我們看到了屏幕後面的世界,那裡面有各種物體,我們看到的是映射在x,y平面上的一個投射圖像。屏幕就像是一個鏡頭一樣,將裡面的物體映射到x,y平面上,成為一個二維的圖像。那麼如果,我們把屏幕這個鏡頭沿著z軸,拉遠或者拉進,那麼圖像會有什麼變化呢,肯定會變小或者變大。就好比坐在飛機上透過窗口看地面的汽車,和在地面上看到的大小是不同的。
結論就是,在屏幕上顯示的像素,不僅僅有x,y坐標,其實還有z軸的影響。所以這裡對應的像素描述由一個3行一列的矩陣來表示:
x,y分別代表x,y軸上的坐標,而1代表屏幕在z軸上的坐標為默認的。如果將1變大,那麼屏幕會拉遠, 圖形會變小。
現在我們來看看matrix怎麼作用於每個像素的值。這裡需要用到矩陣的乘法,首先需要明確的是,矩陣的前乘和後乘是不相同的,也就是說不滿足乘法交換律。
這裡我們通過一個旋轉變換來看看原理,其實一張圖片圍繞一個點旋轉,也就是所有的點都圍繞一個點旋轉,所以只需要關注一個點的情況即可:
假定有一個點 ,相對坐標原點順時針旋轉後的情形,同時假定P點離坐標原點的距離為r,如下圖:
那麼就有:
換做矩陣運算就如下圖:
從這裡就可以看出,矩陣中的值,是如何作用於像素點的x,y坐標以及z軸遠近。
同時,可以看到,上面的矩陣四塊區域的切分也是因為矩陣乘法的操作決定的,由於這裡的乘法運算中,左上角的四個值,可以和x,y值做乘法運算,所以可以影響到旋轉等操作,而右上角的模塊,只能做加法,所以只能影響到平移。右下角的模塊主要管z軸,自然就可以進行等比的縮放了,左下角的模塊一般不去動他,否則會把x,y值加入到z軸中來,會不可控。
講解完了matrix作用於像素點的原理之後,我們逐個講解它的方法。
public Matrix()
public Matrix(Matrix src)
構造函數有兩個,第一個是直接創建一個單位矩陣,第二個是根據提供的矩陣創建一個新的矩陣(采用deep copy)
單位矩陣如下:
public boolean isIdentity()//判斷是否是單位矩陣
public boolean isAffine()//判斷是否是仿射矩陣
是否是單位矩陣很簡單,就不做講解了,這裡是否是仿射矩陣可能大家不好理解。
首先來看看什麼是仿射變換。仿射變換其實就是二維坐標到二維坐標的線性變換,保持二維圖形的“平直性”(即變換後直線還是直線不會打彎,圓弧還是圓弧)和“平行性”(指保持二維圖形間的相對位置關系不變,平行線還是平行線,而直線上點的位置順序不變),可以通過一系列的原子變換的復合來實現,原子變換就包括:平移、縮放、翻轉、旋轉和錯切。這裡除了透視可以改變z軸以外,其他的變換基本都是上述的原子變換,所以,只要最後一行是0,0,1則是仿射矩陣。
public boolean rectStaysRect()
判斷該矩陣是否可以將一個矩形依然變換為一個矩形。當矩陣是單位矩陣,或者只進行平移,縮放,以及旋轉90度的倍數的時候,返回true。
public void reset()
重置矩陣為單位矩陣。
public void setTranslate(float dx, float dy)
設置平移效果,參數分別是x,y上的平移量。
效果圖如下:
代碼如下:
Matrix matrix = new Matrix();
canvas.drawBitmap(bitmap, matrix, paint);
matrix.setTranslate(100, 1000);
canvas.drawBitmap(bitmap, matrix, paint);
public void setScale(float sx, float sy, float px, float py)
public void setScale(float sx, float sy)
兩個方法都是設置縮放到matrix中,sx,sy代表了縮放的倍數,px,py代表縮放的中心。這裡跟上面比較類似不做講解了。
public void setRotate(float degrees, float px, float py)
public void setRotate(float degrees)
和上面類似,不再講解。
public void setSinCos(float sinValue, float cosValue, float px, float py)
public void setSinCos(float sinValue, float cosValue)
這個方法乍一看可能有點蒙,其實在前面的原理中,我們講解了一個旋轉的例子,他最終的矩陣效果是這樣的:
其實旋轉,就是使用了這樣的matrix,顯而易見,這裡的參數就清晰了。
sinValue:對應圖中的sin值
cosValue:對應cos值
px:中心的x坐標
py:中心的y坐標
看一個示例,我們把圖像旋轉90度,那麼90度對應的sin和cos分別是1和0。
看代碼如下:
Matrixmatrix = new Matrix();
matrix.setSinCos(1, 0, bitmap.getWidth() / 2, bitmap.getHeight() / 2);
canvas.drawBitmap(bitmap, matrix, paint);
public void setSkew(float kx, float ky, float px, float py)
public void setSkew(float kx, float ky)
錯切,這裡kx,ky分別代表了x,y上的錯切因子,px,py代表了錯切的中心。不了解錯切了在前面canvas變換中去查看,這裡不再講解。
public boolean setConcat(Matrix a,Matrix b)
將當前matrix的值變為a和b的乘積,它的意義在下面的 進階方法中來探討。
上面的基本方法中,有關於變換的set方法都可以帶來不同的效果,但是每個set都會把上個效果清除掉,例如依次調用了setSkew,setTranslate,那麼最終只有setTranslate會起作用,那麼如何才和將兩種效果復合呢。Matrix給我們提供了很多方法。但是主要都是2類:
preXXXX:以pre開頭,例如preTranslate
postXXXX:以post開頭,例如postScale
他們分別代表了前乘,和後乘。看一段代碼:
Matrix matrix = new Matrix();
matrix.setTranslate(100, 1000);
matrix.preScale(0.5f, 0.5f);
這裡matrix前乘了一個scale矩陣,換算成數學式如下:
從上面可以看出,最終得出的matrix既包含了縮放信息也有平移信息。
後乘自然就是matrix在後面,而縮放矩陣在前面,由於矩陣前後乘並不等價,也就導致了他們的效果不同。我們來看看後乘的結果:
可以看到,結果跟上面不同,並且這也不是我們想要的結果,這裡縮放沒有更改,但是平移被減半了,換句話說,平移的距離也被縮放了。所以需要注意前後乘法的關系。
來看看他們對應的效果圖:
前乘:
後乘:
可以明顯看到,後乘的平移距離受了影響。
了解清除了前後乘的意義,在使用的過程中,多個效果的疊加時,一樣要注意,否則效果達不到預期。
後面一篇我們繼續講解matrix的高階用法
現在,不少人都在手機搜狗輸入法,但是有些用戶反映,在手機上使用搜狗輸入法進行書寫時,因為鍵盤大小而有了一些困擾,這裡有一個方法可以調節鍵盤大小,方便您的書寫
雖然只是模仿,但我覺得這是學習自定義view的必經之路,所以還是把我所學到的東西拿出來與大家一起分享。先貼出一張progressBar的gif圖,其中有水平的進度條,和圓
一個簡單的畫板,可以繪制,可以選擇顏色,可以保存。 當然了這種工具一般常用的通訊軟件都是會有的,比如QQ, 飛秋等其中我們必須監聽手指的觸摸事件,手指的觸摸事件就分為3種
實現原理首先就是自定義個WaveView 繼承View,然後再WaveView 內部實現代碼邏輯: ① 水波就