自定義View進(jìn)階篇《十》——Matrix詳解

這應(yīng)該是目前最詳細(xì)的一篇講解Matrix的中文文章了,在上一篇文章Matrix原理中竹习,我們對(duì)Matrix做了一個(gè)簡(jiǎn)單的了解誊抛,偏向理論,在本文中則會(huì)詳細(xì)的講解Matrix的具體用法整陌,以及與Matrix相關(guān)的一些實(shí)用技巧拗窃。

?? 警告:測(cè)試本文章示例之前請(qǐng)關(guān)閉硬件加速。

Matrix方法表

按照慣例泌辫,先放方法表做概覽随夸。


Matrix方法詳解

構(gòu)造方法

構(gòu)造方法沒有在上面表格中列出。

無(wú)參構(gòu)造
Matrix ()

創(chuàng)建一個(gè)全新的Matrix震放,使用格式如下:

Matrix matrix = new Matrix();

通過這種方式創(chuàng)建出來(lái)的并不是一個(gè)數(shù)值全部為空的矩陣宾毒,而是一個(gè)單位矩陣,如下:


有參構(gòu)造
Matrix (Matrix src)

這種方法則需要一個(gè)已經(jīng)存在的矩陣作為參數(shù),使用格式如下:

Matrix matrix = new Matrix(src);

創(chuàng)建一個(gè)Matrix殿遂,并對(duì)src深拷貝(理解為新的matrix和src是兩個(gè)對(duì)象诈铛,但內(nèi)部數(shù)值相同即可)禽最。

基本方法

基本方法內(nèi)容比較簡(jiǎn)單敢课,在此處簡(jiǎn)要介紹一下尚氛。

1.equals

比較兩個(gè)Matrix的數(shù)值是否相同携兵。

2.hashCode

獲取Matrix的哈希值闻葵。

3.toString

將Matrix轉(zhuǎn)換為字符串: Matrix{[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]}

4.toShortString

將Matrix轉(zhuǎn)換為短字符串: [1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]

數(shù)值操作

數(shù)值操作這一組方法可以幫助我們直接控制Matrix里面的數(shù)值鲸湃。

1.set
void set (Matrix src)

沒有返回值浓镜,有一個(gè)參數(shù)锭魔,作用是將參數(shù)Matrix的數(shù)值復(fù)制到當(dāng)前Matrix中。如果參數(shù)為空咬荷,則重置當(dāng)前Matrix冠句,相當(dāng)于reset()。

2.reset
void reset ()

重置當(dāng)前Matrix(將當(dāng)前Matrix重置為單位矩陣)幸乒。

3.setValues
void setValues (float[] values)

setValues的參數(shù)是浮點(diǎn)型的一維數(shù)組懦底,長(zhǎng)度需要大于9,拷貝數(shù)組中的前9位數(shù)值賦值給當(dāng)前Matrix罕扎。

4.getValues
void getValues (float[] values)

很顯然聚唐,getValues和setValues是一對(duì)方法,參數(shù)也是浮點(diǎn)型的一維數(shù)組腔召,長(zhǎng)度需要大于9杆查,將Matrix中的數(shù)值拷貝進(jìn)參數(shù)的前9位中。

數(shù)值計(jì)算
1.mapPoints
void mapPoints (float[] pts)

void mapPoints (float[] dst, float[] src)

void mapPoints (float[] dst, int dstIndex,float[] src, int srcIndex, int pointCount)

計(jì)算一組點(diǎn)基于當(dāng)前Matrix變換后的位置臀蛛,(由于是計(jì)算點(diǎn)亲桦,所以參數(shù)中的float數(shù)組長(zhǎng)度一般都是偶數(shù)的,若為奇數(shù),則最后一個(gè)數(shù)值不參與計(jì)算)浊仆。

它有三個(gè)重載方法:

(1) void mapPoints (float[] pts) 方法僅有一個(gè)參數(shù)客峭,pts數(shù)組作為參數(shù)傳遞原始數(shù)值,計(jì)算結(jié)果仍存放在pts中抡柿。

示例:

// 初始數(shù)據(jù)為三個(gè)點(diǎn) (0, 0) (80, 100) (400, 300) 
float[] pts = new float[]{0, 0, 80, 100, 400, 300};

// 構(gòu)造一個(gè)matrix舔琅,x坐標(biāo)縮放0.5
Matrix matrix = new Matrix();
matrix.setScale(0.5f, 1f);

// 輸出pts計(jì)算之前數(shù)據(jù)
Log.i(TAG, "before: "+ Arrays.toString(pts));

// 調(diào)用map方法計(jì)算
matrix.mapPoints(pts);

// 輸出pts計(jì)算之后數(shù)據(jù)
Log.i(TAG, "after : "+ Arrays.toString(pts));

結(jié)果:

before: [0.0, 0.0, 80.0, 100.0, 400.0, 300.0]
after : [0.0, 0.0, 40.0, 100.0, 200.0, 300.0]

(2) void mapPoints (float[] dst, float[] src) ,src作為參數(shù)傳遞原始數(shù)值洲劣,計(jì)算結(jié)果存放在dst中备蚓,src不變。

如果原始數(shù)據(jù)需要保留則一般使用這種方法闪檬。

示例:

// 初始數(shù)據(jù)為三個(gè)點(diǎn) (0, 0) (80, 100) (400, 300)
float[] src = new float[]{0, 0, 80, 100, 400, 300};
float[] dst = new float[6];

// 構(gòu)造一個(gè)matrix星著,x坐標(biāo)縮放0.5
Matrix matrix = new Matrix();
matrix.setScale(0.5f, 1f);

// 輸出計(jì)算之前數(shù)據(jù)
Log.i(TAG, "before: src="+ Arrays.toString(src));
Log.i(TAG, "before: dst="+ Arrays.toString(dst));

// 調(diào)用map方法計(jì)算
matrix.mapPoints(dst,src);

// 輸出計(jì)算之后數(shù)據(jù)
Log.i(TAG, "after : src="+ Arrays.toString(src));
Log.i(TAG, "after : dst="+ Arrays.toString(dst));

結(jié)果:

before: src=[0.0, 0.0, 80.0, 100.0, 400.0, 300.0]
before: dst=[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
after : src=[0.0, 0.0, 80.0, 100.0, 400.0, 300.0]
after : dst=[0.0, 0.0, 40.0, 100.0, 200.0, 300.0]

(3) void mapPoints (float[] dst, int dstIndex,float[] src, int srcIndex, int pointCount) 可以指定只計(jì)算一部分?jǐn)?shù)值购笆。



示例:
將第二粗悯、三個(gè)點(diǎn)計(jì)算后存儲(chǔ)進(jìn)dst最開始位置。

// 初始數(shù)據(jù)為三個(gè)點(diǎn) (0, 0) (80, 100) (400, 300)
float[] src = new float[]{0, 0, 80, 100, 400, 300};
float[] dst = new float[6];

// 構(gòu)造一個(gè)matrix同欠,x坐標(biāo)縮放0.5
Matrix matrix = new Matrix();
matrix.setScale(0.5f, 1f);

// 輸出計(jì)算之前數(shù)據(jù)
Log.i(TAG, "before: src="+ Arrays.toString(src));
Log.i(TAG, "before: dst="+ Arrays.toString(dst));

// 調(diào)用map方法計(jì)算(最后一個(gè)2表示兩個(gè)點(diǎn)样傍,即四個(gè)數(shù)值,并非兩個(gè)數(shù)值)
matrix.mapPoints(dst, 0, src, 2, 2);

// 輸出計(jì)算之后數(shù)據(jù)
Log.i(TAG, "after : src="+ Arrays.toString(src));
Log.i(TAG, "after : dst="+ Arrays.toString(dst));

結(jié)果:

before: src=[0.0, 0.0, 80.0, 100.0, 400.0, 300.0]
before: dst=[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
after : src=[0.0, 0.0, 80.0, 100.0, 400.0, 300.0]
after : dst=[40.0, 100.0, 200.0, 300.0, 0.0, 0.0]
2.mapRadius
float mapRadius (float radius)

測(cè)量半徑,由于圓可能會(huì)因?yàn)楫嫴甲儞Q變成橢圓铺遂,所以此處測(cè)量的是平均半徑衫哥。

示例:

float radius = 100;
float result = 0;

// 構(gòu)造一個(gè)matrix,x坐標(biāo)縮放0.5
Matrix matrix = new Matrix();
matrix.setScale(0.5f, 1f);

Log.i(TAG, "mapRadius: "+radius);

result = matrix.mapRadius(radius);

Log.i(TAG, "mapRadius: "+result);

結(jié)果:

mapRadius: 100.0
mapRadius: 70.71068
3.mapRect
boolean mapRect (RectF rect)

boolean mapRect (RectF dst, RectF src)

測(cè)量矩形變換后位置襟锐。
(1) boolean mapRect (RectF rect) 測(cè)量rect并將測(cè)量結(jié)果放入rect中撤逢,返回值是判斷矩形經(jīng)過變換后是否仍為矩形。
示例:

RectF rect = new RectF(400, 400, 1000, 800);

// 構(gòu)造一個(gè)matrix
Matrix matrix = new Matrix();
matrix.setScale(0.5f, 1f);
matrix.postSkew(1,0);

Log.i(TAG, "mapRadius: "+rect.toString());

boolean result = matrix.mapRect(rect);

Log.i(TAG, "mapRadius: "+rect.toString());
Log.e(TAG, "isRect: "+ result);

結(jié)果:

mapRadius: RectF(400.0, 400.0, 1000.0, 800.0)
mapRadius: RectF(600.0, 400.0, 1300.0, 800.0)
isRect: false

由于使用了錯(cuò)切,所以返回結(jié)果為false蚊荣。

(2) boolean mapRect (RectF dst, RectF src) 測(cè)量src并將測(cè)量結(jié)果放入dst中初狰,返回值是判斷矩形經(jīng)過變換后是否仍為矩形,和之前沒有什么太大區(qū)別,此處就不啰嗦了互例。

4.mapVectors

測(cè)量向量奢入。

void mapVectors (float[] vecs)

void mapVectors (float[] dst, float[] src)

void mapVectors (float[] dst, int dstIndex, float[] src, int srcIndex, int vectorCount)

mapVectors 與 mapPoints 基本上是相同的,可以直接參照上面的mapPoints使用方法媳叨。

而兩者唯一的區(qū)別就是mapVectors不會(huì)受到位移的影響腥光,這符合向量的定律,如果你不了解的話糊秆,請(qǐng)找到以前教過你的老師然后把學(xué)費(fèi)要回來(lái)武福。

區(qū)別:

float[] src = new float[]{1000, 800};
float[] dst = new float[2];

// 構(gòu)造一個(gè)matrix
Matrix matrix = new Matrix();
matrix.setScale(0.5f, 1f);
matrix.postTranslate(100,100);

// 計(jì)算向量, 不受位移影響
matrix.mapVectors(dst, src);
Log.i(TAG, "mapVectors: "+Arrays.toString(dst));

// 計(jì)算點(diǎn)
matrix.mapPoints(dst, src);
Log.i(TAG, "mapPoints: "+Arrays.toString(dst));

結(jié)果:

mapVectors: [500.0, 800.0]
mapPoints: [600.0, 900.0]
set、pre 與 post

對(duì)于四種基本變換 平移(translate)痘番、縮放(scale)艘儒、旋轉(zhuǎn)(rotate)、 錯(cuò)切(skew) 它們每一種都三種操作方法夫偶,分別為 設(shè)置(set)界睁、 前乘(pre) 和 后乘 (post)。而它們的基礎(chǔ)是Concat兵拢,通過先構(gòu)造出特殊矩陣然后用原始矩陣Concat特殊矩陣翻斟,達(dá)到變換的結(jié)果。
關(guān)于四種基本變換的知識(shí)和三種對(duì)應(yīng)操作的區(qū)別说铃,詳細(xì)可以參考 Canvas之畫布操作 和 Matrix原理 這兩篇文章的內(nèi)容访惜。

由于之前的文章已經(jīng)詳細(xì)的講解過了它們的原理與用法,所以此處就簡(jiǎn)要的介紹一下:



Matrix 相關(guān)的重要知識(shí):

  • 1.一開始從Canvas中獲取到到Matrix并不是初始矩陣腻扇,而是經(jīng)過偏移后到矩陣债热,且偏移距離就是距離屏幕左上角的位置。
    這個(gè)可以用于判定View在屏幕上的絕對(duì)位置幼苛,View可以根據(jù)所處位置做出調(diào)整窒篱。
  • 2.構(gòu)造Matrix時(shí)使用的是矩陣乘法,前乘(pre)與后乘(post)結(jié)果差別很大舶沿。
  • 3.受矩陣乘法影響墙杯,后面的執(zhí)行的操作可能會(huì)影響到之前的操作。
    使用時(shí)需要注意構(gòu)造順序括荡。
特殊方法

這一類方法看似不起眼高镐,但拿來(lái)稍微加工一下就可能制作意想不到的效果。

1.setPolyToPoly
boolean setPolyToPoly (
        float[] src,    // 原始數(shù)組 src [x,y]畸冲,存儲(chǔ)內(nèi)容為一組點(diǎn)
        int srcIndex,   // 原始數(shù)組開始位置
        float[] dst,    // 目標(biāo)數(shù)組 dst [x,y]嫉髓,存儲(chǔ)內(nèi)容為一組點(diǎn)
        int dstIndex,   // 目標(biāo)數(shù)組開始位置
        int pointCount) // 測(cè)控點(diǎn)的數(shù)量 取值范圍是: 0到4

Poly全稱是Polygon观腊,多邊形的意思,了解了意思大致就能知道這個(gè)方法是做什么用的了算行,應(yīng)該與PS中自由變換中的扭曲有點(diǎn)類似恕沫。



從參數(shù)我們可以了解到setPolyToPoly最多可以支持4個(gè)點(diǎn),這四個(gè)點(diǎn)通常為圖形的四個(gè)角纱意,可以通過這四個(gè)角將視圖從矩形變換成其他形狀婶溯。

簡(jiǎn)單示例:

public class MatrixSetPolyToPolyTest extends View {

    private Bitmap mBitmap;             // 要繪制的圖片
    private Matrix mPolyMatrix;         // 測(cè)試setPolyToPoly用的Matrix

    public MatrixSetPolyToPolyTest(Context context) {
        super(context);

        initBitmapAndMatrix();
    }

    private void initBitmapAndMatrix() {
        mBitmap = BitmapFactory.decodeResource(getResources(),
                R.drawable.poly_test);

        mPolyMatrix = new Matrix();


        float[] src = {0, 0,                                    // 左上
                mBitmap.getWidth(), 0,                          // 右上
                mBitmap.getWidth(), mBitmap.getHeight(),        // 右下
                0, mBitmap.getHeight()};                        // 左下

        float[] dst = {0, 0,                                    // 左上
                mBitmap.getWidth(), 400,                        // 右上
                mBitmap.getWidth(), mBitmap.getHeight() - 200,  // 右下
                0, mBitmap.getHeight()};                        // 左下

        // 核心要點(diǎn)
        mPolyMatrix.setPolyToPoly(src, 0, dst, 0, src.length >> 1); // src.length >> 1 為位移運(yùn)算 相當(dāng)于處以2

        // 此處為了更好的顯示對(duì)圖片進(jìn)行了等比縮放和平移(圖片本身有點(diǎn)大)
        mPolyMatrix.postScale(0.26f, 0.26f);
        mPolyMatrix.postTranslate(0,200);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // 根據(jù)Matrix繪制一個(gè)變換后的圖片
        canvas.drawBitmap(mBitmap, mPolyMatrix, null);
    }
}

我們知道pointCount支持點(diǎn)的個(gè)數(shù)為0到4個(gè),四個(gè)一般指圖形的四個(gè)角偷霉,屬于最常用的一種情形迄委,但前面幾種是什么情況呢?


從上表我們可以觀察出一個(gè)規(guī)律, 隨著pointCount數(shù)值增大setPolyToPoly的可以操作性也越來(lái)越強(qiáng)类少,這不是廢話么叙身,可調(diào)整點(diǎn)數(shù)多了能干的事情自然也多了。

測(cè)控點(diǎn)選取位置?

測(cè)控點(diǎn)可以選擇任何你認(rèn)為方便的位置硫狞,只要src與dst一一對(duì)應(yīng)即可信轿。不過為了方便,通常會(huì)選擇一些特殊的點(diǎn): 圖形的四個(gè)角残吩,邊線的中心點(diǎn)以及圖形的中心點(diǎn)等财忽。不過有一點(diǎn)需要注意,測(cè)控點(diǎn)選取都應(yīng)當(dāng)是不重復(fù)的(src與dst均是如此)泣侮,如果選取了重復(fù)的點(diǎn)會(huì)直接導(dǎo)致測(cè)量失效即彪,這也意味著,你不允許將一個(gè)方形(四個(gè)點(diǎn))映射為三角形(四個(gè)點(diǎn)活尊,但其中兩個(gè)位置重疊)隶校,但可以接近于三角形。

作用范圍?

作用范圍當(dāng)然是設(shè)置了Matrix的全部區(qū)域蛹锰,如果你將這個(gè)Matrix賦值給了Canvas深胳,它的作用范圍就是整個(gè)畫布,如果你賦值給了Bitmap铜犬,它的作用范圍就是整張圖片舞终。
接下來(lái)用示例演示一下,所有示例的src均為圖片大小翎苫,dst根據(jù)手勢(shì)變化权埠。

pointCount為0

pointCount為0和reset是等價(jià)的榨了,而不是保持matrix不變煎谍,在最底層的實(shí)現(xiàn)中可以看到這樣的代碼:

if (0 == count) {
    this->reset();
    return true;
}
pointCount為1

pointCount為1和translate是等價(jià)的,在最底層的實(shí)現(xiàn)中可以看到這樣的代碼:

if (1 == count) {
    this->setTranslate(dst[0].fX - src[0].fX, dst[0].fY - src[0].fY);
    return true;
}

平移的距離是dst - src.

當(dāng)測(cè)控點(diǎn)為1的時(shí)候龙屉,由于你只有一個(gè)點(diǎn)可以控制呐粘,所以你只能拖拽著它在2D平面上滑動(dòng)满俗。


pointCount為2

當(dāng)pointCount為2的時(shí)候,可以做縮放作岖、平移和旋轉(zhuǎn)唆垃。


pointCount為3

當(dāng)pointCount為3的時(shí)候,可以做縮放痘儡、平移辕万、旋轉(zhuǎn)和錯(cuò)切。


pointCount為4

當(dāng)pointCount為4的時(shí)候沉删,你可以將圖像拉伸為任意四邊形渐尿。


上面已經(jīng)用圖例比較詳細(xì)的展示了不同操控點(diǎn)個(gè)數(shù)的情況,如果你依舊存在疑問矾瑰,可以獲取代碼自己試一下砖茸。
點(diǎn)擊此處查看setPolyToPoly測(cè)試代碼

2.setRectToRect
boolean setRectToRect (RectF src,           // 源區(qū)域
                RectF dst,                  // 目標(biāo)區(qū)域
                Matrix.ScaleToFit stf)      // 縮放適配模式

簡(jiǎn)單來(lái)說(shuō)就是將源矩形的內(nèi)容填充到目標(biāo)矩形中,然而在大多數(shù)的情況下殴穴,源矩形和目標(biāo)矩形的長(zhǎng)寬比是不一致的凉夯,到底該如何填充呢,這個(gè)填充的模式就由第三個(gè)參數(shù) stf 來(lái)確定采幌。

ScaleToFit 是一個(gè)枚舉類型劲够,共包含了四種模式:



下面我們看一下不同寬高比的src與dst在不同模式下是怎樣的。
假設(shè)灰色部分是dst休傍,橙色部分是src再沧,由于是測(cè)試不同寬高比,示例中讓dst保持不變尊残,看兩種寬高比的src在不同模式下填充的位置炒瘸。



下面用代碼演示一下居中的示例:
public class MatrixSetRectToRectTest extends View {

    private static final String TAG = "MatrixSetRectToRectTest";

    private int mViewWidth, mViewHeight;

    private Bitmap mBitmap;             // 要繪制的圖片
    private Matrix mRectMatrix;         // 測(cè)試etRectToRect用的Matrix

    public MatrixSetRectToRectTest(Context context) {
        super(context);

        mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.rect_test);
        mRectMatrix = new Matrix();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mViewWidth = w;
        mViewHeight = h;

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        RectF src= new RectF(0, 0, mBitmap.getWidth(), mBitmap.getHeight() );
        RectF dst = new RectF(0, 0, mViewWidth, mViewHeight );

        // 核心要點(diǎn)
        mRectMatrix.setRectToRect(src,dst, Matrix.ScaleToFit.CENTER);

        // 根據(jù)Matrix繪制一個(gè)變換后的圖片
        canvas.drawBitmap(mBitmap, mRectMatrix, new Paint());
    }
}
3.rectStaysRect

判斷矩形經(jīng)過變換后是否仍為矩形,假如Matrix進(jìn)行了平移寝衫、縮放則畫布僅僅是位置和大小改變顷扩,矩形變換后仍然為矩形,但Matrix進(jìn)行了非90度倍數(shù)的旋轉(zhuǎn)或者錯(cuò)切慰毅,則矩形變換后就不再是矩形了隘截,這個(gè)很好理解,不過多贅述汹胃,順便說(shuō)一下婶芭,前面的mapRect方法的返回值就是根據(jù)rectStaysRect來(lái)判斷的。

4.setSinCos

設(shè)置sinCos值着饥,這個(gè)是控制Matrix旋轉(zhuǎn)的犀农,由于Matrix已經(jīng)封裝好了Rotate方法,所以這個(gè)并不常用宰掉,在此僅作概述呵哨。

// 方法一
void setSinCos (float sinValue,     // 旋轉(zhuǎn)角度的sin值
                float cosValue)     // 旋轉(zhuǎn)角度的cos值

// 方法二
void setSinCos (float sinValue,     // 旋轉(zhuǎn)角度的sin值
                float cosValue,     // 旋轉(zhuǎn)角度的cos值
                float px,           // 中心位置x坐標(biāo)
                float py)           // 中心位置y坐標(biāo)

簡(jiǎn)單測(cè)試:

Matrix matrix = new Matrix();
// 旋轉(zhuǎn)90度
// sin90=1
// cos90=0
matrix.setSinCos(1f, 0f);

Log.i(TAG, "setSinCos:"+matrix.toShortString());

// 重置
matrix.reset();

// 旋轉(zhuǎn)90度
matrix.setRotate(90);

Log.i(TAG, "setRotate:"+matrix.toShortString());

結(jié)果:

setSinCos:[0.0, -1.0, 0.0][1.0, 0.0, 0.0][0.0, 0.0, 1.0]
setRotate:[0.0, -1.0, 0.0][1.0, 0.0, 0.0][0.0, 0.0, 1.0]
矩陣相關(guān)

矩陣相關(guān)的函數(shù)就屬于哪一種非沉薇簦靠近底層的東西了,大部分開發(fā)者很少直接接觸這些東西孟害,想要弄明白這個(gè)可以回去請(qǐng)教你們的線性代數(shù)老師拒炎,這里也僅作概述。


1.invert

求矩陣的逆矩陣挨务,簡(jiǎn)而言之就是計(jì)算與之前相反的矩陣击你,如果之前是平移200px,則求的矩陣為反向平移200px谎柄,如果之前是縮小到0.5f果漾,則結(jié)果是放大到2倍。

boolean invert (Matrix inverse)

簡(jiǎn)單測(cè)試:

Matrix matrix = new Matrix();
Matrix invert = new Matrix();
matrix.setTranslate(200,500);

Log.e(TAG, "before - matrix "+matrix.toShortString() );

Boolean result = matrix.invert(invert);

Log.e(TAG, "after  - result "+result );
Log.e(TAG, "after  - matrix "+matrix.toShortString() );
Log.e(TAG, "after  - invert "+invert.toShortString() );

結(jié)果:

before - matrix [1.0, 0.0, 200.0][0.0, 1.0, 500.0][0.0, 0.0, 1.0]
after  - result true
after  - matrix [1.0, 0.0, 200.0][0.0, 1.0, 500.0][0.0, 0.0, 1.0]
after  - invert [1.0, 0.0, -200.0][0.0, 1.0, -500.0][0.0, 0.0, 1.0]
2.isAffine

判斷矩陣是否是仿射矩陣, 貌似并沒有太大卵用谷誓,因?yàn)槟銦o(wú)論如何操作結(jié)果始終都為true绒障。

這是為什么呢?因?yàn)槠駷橹刮覀兪褂玫乃凶儞Q都是仿射變換捍歪,那變換出來(lái)的矩陣自然是仿射矩陣嘍户辱。

判斷是否是仿射矩陣最重要的一點(diǎn)就是,直線是否仍為直線糙臼,簡(jiǎn)單想一下就知道庐镐,不論平移,旋轉(zhuǎn)变逃,錯(cuò)切必逆,縮放,直線變換后最終仍為直線揽乱,要想讓isAffine的結(jié)果變?yōu)閒alse名眉,除非你能把直線掰彎,我目前還沒有找到能夠掰彎的方法凰棉,所以我仍是直男(就算找到了损拢,我依舊是直男)。

簡(jiǎn)單測(cè)試:

Matrix matrix = new Matrix();
Log.i(TAG,"isAffine="+matrix.isAffine());

matrix.postTranslate(200,0);
matrix.postScale(0.5f, 1);
matrix.postSkew(0,1);
matrix.postRotate(56);

Log.i(TAG,"isAffine="+matrix.isAffine());

結(jié)果:

isAffine=true
isAffine=true

3.isIdentity
判斷是否為單位矩陣撒犀,什么是單位矩陣呢福压,就是文章一開始的那個(gè):



新創(chuàng)建的Matrix和重置后的Matrix都是單位矩陣,不過或舞,只要隨意操作一步荆姆,就不在是單位矩陣了。
簡(jiǎn)單測(cè)試:

Matrix matrix = new Matrix();
Log.i(TAG,"isIdentity="+matrix.isIdentity());

matrix.postTranslate(200,0);

Log.i(TAG,"isIdentity="+matrix.isIdentity());

結(jié)果:

isIdentity=true
isIdentity=false
Matrix實(shí)用技巧

通過前面的代碼和示例映凳,我們已經(jīng)了解了Matrix大部分方法是如何使用的胆筒,這些基本的原理和方法通過組合可能會(huì)創(chuàng)造出神奇的東西,網(wǎng)上有很多教程講Bitmap利用Matrix變換來(lái)制作鏡像倒影等魏宽,這都屬于Matrix的基本應(yīng)用腐泻,我就不在贅述了决乎,下面我簡(jiǎn)要介紹幾種然并卵的小技巧队询,更多的大家可以開啟自己的腦洞來(lái)發(fā)揮派桩。

1.獲取View在屏幕上的絕對(duì)位置

在之前的文章Matrix原理中我們提到過Matrix最根本的作用就是坐標(biāo)映射,將View的相對(duì)坐標(biāo)映射為屏幕的絕對(duì)坐標(biāo)蚌斩,也提到過我們?cè)趏nDraw函數(shù)的canvas中獲取到到Matrix并不是單位矩陣铆惑,結(jié)合這兩點(diǎn),聰明的你肯定想到了我們可以從canvas的Matrix入手取得View在屏幕上的絕對(duì)位置送膳。
不過员魏,這也僅僅是一個(gè)然并卵的小技巧而已,使用getLocationOnScreen
同樣可以獲取View在屏幕的位置叠聋,但如果你是想讓下一任接盤俠弄不明白你在做什么或者是被同事打死的話撕阎,盡管這么做。
簡(jiǎn)單示例:

@Override
protected void onDraw(Canvas canvas) {
    float[] values = new float[9];
    int[] location1 = new int[2];

    Matrix matrix = canvas.getMatrix();
    matrix.getValues(values);

    location1[0] = (int) values[2];
    location1[1] = (int) values[5];
    Log.i(TAG, "location1 = " + Arrays.toString(location1));

    int[] location2 = new int[2];
    this.getLocationOnScreen(location2);
    Log.i(TAG, "location2 = " + Arrays.toString(location2));
}

結(jié)果:

location1 = [0, 243]
location2 = [0, 243]
2.利用setPolyToPoly制造3D效果

這個(gè)全憑大家想象力啦碌补,不過我搜了一下還真搜到了好東西虏束,之前鴻洋大大發(fā)過一篇博文詳細(xì)講解了利用setPolyToPoly制造的折疊效果布局,大家直接到他的博客去看吧厦章,我就不寫了镇匀。

圖片引用自鴻洋大大的博客,稍作了一下處理袜啃。

博文鏈接:

Android FoldingLayout 折疊布局 原理及實(shí)現(xiàn)(一)
Android FoldingLayout 折疊布局 原理及實(shí)現(xiàn)(二)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末汗侵,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子群发,更是在濱河造成了極大的恐慌晰韵,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,640評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件熟妓,死亡現(xiàn)場(chǎng)離奇詭異宫屠,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)滑蚯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門浪蹂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人告材,你說(shuō)我怎么就攤上這事坤次。” “怎么了斥赋?”我有些...
    開封第一講書人閱讀 165,011評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵缰猴,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我疤剑,道長(zhǎng)滑绒,這世上最難降的妖魔是什么闷堡? 我笑而不...
    開封第一講書人閱讀 58,755評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮疑故,結(jié)果婚禮上杠览,老公的妹妹穿的比我還像新娘。我一直安慰自己纵势,他們只是感情好踱阿,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,774評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著钦铁,像睡著了一般软舌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上牛曹,一...
    開封第一講書人閱讀 51,610評(píng)論 1 305
  • 那天佛点,我揣著相機(jī)與錄音,去河邊找鬼黎比。 笑死超营,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的焰手。 我是一名探鬼主播糟描,決...
    沈念sama閱讀 40,352評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼书妻!你這毒婦竟也來(lái)了船响?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,257評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤躲履,失蹤者是張志新(化名)和其女友劉穎见间,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體工猜,經(jīng)...
    沈念sama閱讀 45,717評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡米诉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,894評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了篷帅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片史侣。...
    茶點(diǎn)故事閱讀 40,021評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖魏身,靈堂內(nèi)的尸體忽然破棺而出惊橱,到底是詐尸還是另有隱情,我是刑警寧澤箭昵,帶...
    沈念sama閱讀 35,735評(píng)論 5 346
  • 正文 年R本政府宣布税朴,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏正林。R本人自食惡果不足惜泡一,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,354評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望觅廓。 院中可真熱鬧鼻忠,春花似錦、人聲如沸哪亿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蝇棉。三九已至,卻和暖如春芥永,著一層夾襖步出監(jiān)牢的瞬間篡殷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工埋涧, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留板辽,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,224評(píng)論 3 371
  • 正文 我出身青樓棘催,卻偏偏與公主長(zhǎng)得像劲弦,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子醇坝,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,974評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容