★60.自定義控件 ★15.Matrix詳解

構造方法

Matrix ()
Matrix (Matrix src)

基本方法

  1. equals():比較兩個Matrix的數值是否相同。
  2. hashCode():獲取Matrix的哈希值。
  3. toString():將Matrix轉換為字符串: Matrix{[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]}
  4. toShortString():將Matrix轉換為短字符串: [1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]

數值操作

set

沒有返回值,有一個參數,作用是將參數Matrix的數值復制到當前Matrix中。如果參數為空,則重置當前Matrix,相當于reset()

void set (Matrix src)

reset

重置當前Matrix(將當前Matrix重置為單位矩陣)。

void reset ()

setValues

setValues()的參數是浮點型的一維數組,長度需要大于9,拷貝數組中的前9位數值賦值給當前Matrix

void setValues(float[] values)

getValues

參數是浮點型的一維數組,長度需要大于9,將Matrix中的數值拷貝進參數的前9位中。

void getValues(float[] values)

數值計算

mapPoints

計算一組點基于當前Matrix變換后的位置,(由于是計算點,所以參數中的float數組長度一般都是偶數的,若為奇數,則最后一個數值不參與計算)。

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

方法一

void mapPoints (float[] pts) 方法僅有一個參數,pts數組作為參數傳遞原始數值,計算結果仍存放在pts中。

方法二

void mapPoints (float[] dst, float[] src)src作為參數傳遞原始數值,計算結果存放在dst中,src不變。

方法三

void mapPoints (float[] dst, int dstIndex,float[] src, int srcIndex, int pointCount) 可以指定只計算一部分數值。

參數 摘要
dst 目標數據
dstIndex 目標數據存儲位置起始下標
src 源數據
srcIndex 源數據存儲位置起始下標
pointCount 計算的點個數

mapRadius

測量半徑,由于圓可能會因為畫布變換變成橢圓,所以此處測量的是平均半徑。

方法

float mapRadius(float radius)

示例

float radius = 100;
float result = 0;

// 構造一個matrix,x坐標縮放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);
mapRadius: 100.0
mapRadius: 70.71068

mapRect

測量矩形變換后位置,返回值是判斷矩形經過變換后是否仍為矩形,非90度倍數的旋轉也會變成非矩形。

boolean mapRect(RectF rect)
boolean mapRect(RectF dst, RectF src)

方法一

boolean mapRect (RectF rect) 測量rect并將測量結果放入rect中。

方法二

boolean mapRect (RectF dst, RectF src) 測量src并將測量結果放入dst中。

mapVectors

測量向量,mapVectorsmapPoints 基本上是相同的,可以直接參照上面的mapPoints使用方法。兩者唯一的區別就是mapVectors不會受到位移的影響,這符合向量的定律。

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

set、pre 與 post

方法 簡介
set 設置,會覆蓋掉之前的數值,導致之前的操作失效。
pre 前乘,構造矩陣乘式時,往前端壓入乘式因子。
post 后乘,構造矩陣乘式時,往后端壓入乘式因子。

特殊方法

setPolyToPoly

簡介

Poly 全稱是 Polygon ,多邊形的意思。setPolyToPoly()最多可以支持4個點。

boolean setPolyToPoly (
        float[] src,    // 原始數組 src [x,y],存儲內容為一組點
        int srcIndex,   // 原始數組開始位置
        float[] dst,    // 目標數組 dst [x,y],存儲內容為一組點
        int dstIndex,   // 目標數組開始位置
        int pointCount) // 測控點的數量 取值范圍是: 0到4
pointCount 摘要
0 相當于reset
1 可以進行 平移
2 可以進行 縮放、旋轉、平移 變換
3 可以進行 縮放、旋轉、平移、錯切 變換
4 可以進行 縮放、旋轉、平移、錯切以及任何形變

示例

public class MatrixSetPolyToPolyTest extends View {

    private Bitmap mBitmap;             // 要繪制的圖片
    private Matrix mPolyMatrix;         // 測試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()};                        // 左下

        // 核心要點
        mPolyMatrix.setPolyToPoly(src, 0, dst, 0, src.length >> 1); // src.length >> 1 為位移運算 相當于處以2

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

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

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

pointCount為0

pointCount()0reset()是等價的。

pointCount為1

pointCount()1translate是等價的,平移的距離是dst - src

pointCount為2

pointCount2的時候,可以做縮放、平移和旋轉。

pointCount為3

pointCount3的時候,可以做縮放、平移、旋轉和錯切。

pointCount為4

pointCount4的時候,你可以將圖像拉伸為任意四邊形。

setRectToRect

簡介

將源矩形的內容填充到目標矩形中。

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

Matrix.ScaleToFit

模式 摘要
CENTER 居中,對src等比例縮放,將其居中放置在dst中。
START 頂部,對src等比例縮放,將其放置在dst的左上角。
END 底部,對src等比例縮放,將其放置在dst的右下角。
FILL 充滿,拉伸src的寬和高,使其完全填充滿dst。

圖示

src(原始狀態)
CENTER
START
END
FILL

示例

展示居中例子:

public class MatrixSetRectToRectTest extends View {
    private static final String TAG = "MatrixSetRectToRectTest";

    private int mViewWidth, mViewHeight;

    private Bitmap mBitmap;             // 要繪制的圖片
    private Matrix mRectMatrix;         // 測試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 );

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

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

rectStaysRect

判斷矩形經過變換后是否仍為矩形,假如Matrix進行了平移、縮放則畫布僅僅是位置和大小改變,矩形變換后仍然為矩形,但Matrix進行了非90度倍數的旋轉或者錯切,則矩形變換后就不再是矩形了。

setSinCos

簡介

設置sinCos值,這個是控制Matrix旋轉的,由于Matrix已經封裝好了Rotate方法,所以這個并不常用。

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

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

示例

Matrix matrix = new Matrix();
// 旋轉90度
// sin90=1
// cos90=0
matrix.setSinCos(1f, 0f);
Log.i(TAG, "setSinCos:"+matrix.toShortString());
// 重置
matrix.reset();
// 旋轉90度
matrix.setRotate(90);
Log.i(TAG, "setRotate:"+matrix.toShortString());
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]

矩陣相關

方法 摘要
invert 求矩陣的逆矩陣
isAffine 判斷當前矩陣是否為仿射矩陣,API21(5.0)才添加的方法。
isIdentity 判斷當前矩陣是否為單位矩陣。

invert

求矩陣的逆矩陣,簡而言之就是計算與之前相反的矩陣,如果之前是平移200px,則求的矩陣為反向平移200px,如果之前是縮小到0.5f,則結果是放大到2倍。

boolean invert(Matrix inverse)

isAffine

判斷是否是仿射矩陣最重要的一點就是,直線是否仍為直線,簡單想一下就知道,不論平移,旋轉,錯切,縮放,直線變換后最終仍為直線,要想讓isAffine()的結果變為false,除非你能把直線掰彎。

boolean isAffine()

isIdentity

判斷是否為單位矩陣。

實用技巧

獲取View在屏幕上的絕對位置。

@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));
}
location1 = [0, 243]
location2 = [0, 243]

利用setPolyToPoly制造3D效果

Android FoldingLayout 折疊布局 原理及實現(一)
Android FoldingLayout 折疊布局 原理及實現(二)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容