關于ImageView中Matrix的方法setScale()縮放處理

我們經常在項目中使用ImageView的scaleType來設置顯示圖片的顯示方式,其中有一種type是矩陣變化matrix方式我們可能在項目中會相對少用,具體matrix的使用方式,不是文章的重點,可以自行google或者參考一下其他同學寫的文章,主要我們講一下Matrix.setScale()方式在使用過程中踩的坑,同樣可以引申到Matrix的其他方法

參考文章

android matrix 最全方法詳解與進階(完整篇)

基本方法介紹

接下來我們簡單介紹一下Matrix類常用的幾種變化:

  • setTranslate(float dx,float dy):控制Matrix進行平移;
  • setSkew(float kx,float ky,float px,float py):控制Matrix以px,py為軸心進行傾斜,kx,ky為X,Y方向上的傾斜距離;
  • setRotate(float degress):控制Matrix進行旋轉,degress控制旋轉的角度;
  • setRorate(float degress,float px,float py):設置以px,py為軸心進行旋轉,degress控制旋轉角度;
  • setScale(float sx,float sy):設置Matrix進行縮放,sx,sy控制X,Y方向上的縮放比例;
  • setScale(float sx,float sy,float px,float py):設置Matrix以px,py為軸心進行縮放(此處有坑),sx,sy控制X,Y方向上的縮放比例;

當然這里只是set方法,還有相應的preXXX()postXXX()方法,其中的區(qū)別就是pre和post和執(zhí)行的順序有關系,set開頭的方法是直接清除之前Matrix內的所有變化,重新設置一次。

  • set是直接設置Matrix的值,每調用一次,之前Matrix內的所有變化都重置,整個Matrix的數組都會變掉
  • post是后乘,當前的矩陣乘以參數給出的矩陣。可以連續(xù)多次使用post,來完成所需的整個變換
  • pre是前乘,參數給出的矩陣乘以當前的矩陣。所以操作是在當前矩陣的最前面發(fā)生的。

我們知道m(xù)atrix實際上是一個3x3的矩陣,根據線性代數里面的知識,矩陣相乘,前乘和后乘得到的結果是不一樣的,所以我們做的矩陣任何的變化(平移、縮放、旋轉等)本質上都是對matrix矩陣進行操作,理解了這一點,對我們后面的踩坑有莫大的幫助

踩坑

這里講一下在上面setScale(float sx,float sy,float px,float py)在實際應用中的坑,我們先看下Android注釋是怎么解釋這個方法的

Set the matrix to scale by sx and sy, with a pivot point at (px, py).The pivot point is the coordinate that should remain unchanged by the specified transformation.

這里什么意思呢?就是設置matrix根據sx和sy的值進行縮放,那么px和py是什么鬼呢?網絡上很多解釋是解釋成中心點,在這個中心點的基礎上進行縮放,其實不然,后面我們會講到這里為什么會有坑,如果你把這兩個參數當成縮放的中心點來看的話,在實際測試過程中你會發(fā)現圖片并不是在當前中心點縮放,在縮放的同時,位置還會進行偏移(這里行為跟postScale(float sx,float sy,float px,float py)中的px與py不一致,post行為是真的以此處為中心點進行縮放)。這里為什么會這樣呢?坑了我好久,不死心,覺得一定有什么貓膩,所以最好的方式,就是看看他的源碼,看下到底是什么原因導致的

先看下Matrix.java

    /**
     * Set the matrix to scale by sx and sy, with a pivot point at (px, py).
     * The pivot point is the coordinate that should remain unchanged by the
     * specified transformation.
     */
    public void setScale(float sx, float sy, float px, float py) {
        native_setScale(native_instance, sx, sy, px, py);
    }

納尼?調用了native_setScale方法,可能很多人看到這一步需要去看native層的方法就放棄,但是沒有什么能難倒攻城獅,不急,我們接著往下看

    private static native void native_setScale(int native_object,
                                        float sx, float sy, float px, float py);

根據一些jni的知識,我們知道在native層的代碼肯定會有一個native_setScale的方法與之對應,所以我們需要去找到該native層的實現方法,看看他的代碼。那么接下來我們去哪里找呢?可能很多同學會想到去下源碼,可是源碼何其多,網絡情況良好的情況下個幾天都是正常的,這里我推薦一個網站androidxref,這里面有你所需要的各個版本的源碼,并且可以根據查詢條件快速查找,查找也是非常快的。最后我們在Matrix.cpp中找到了

    {"native_setScale","(IFFFF)V", (void*) SkMatrixGlue::setScale__FFFF},

// 對應的方法
    static void setScale__FFFF(JNIEnv* env, jobject clazz, SkMatrix* obj, jfloat sx, jfloat sy, jfloat px, jfloat py) {
        SkScalar sx_ = SkFloatToScalar(sx);
        SkScalar sy_ = SkFloatToScalar(sy);
        SkScalar px_ = SkFloatToScalar(px);
        SkScalar py_ = SkFloatToScalar(py);
        obj->setScale(sx_, sy_, px_, py_);
    }

最后我們看一下obj->setScale(sx_, sy_, px_, py_);的實現

    void SkMatrix::setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
       if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
           this->reset();
       } else {
           fMat[kMScaleX] = sx;
           fMat[kMScaleY] = sy;
           fMat[kMTransX] = px - SkScalarMul(sx, px);
           fMat[kMTransY] = py - SkScalarMul(sy, py);
           fMat[kMPersp2] = kMatrix22Elem;
   
           fMat[kMSkewX]  = fMat[kMSkewY] =
           fMat[kMPersp0] = fMat[kMPersp1] = 0;
   
           this->setTypeMask(kScale_Mask | kTranslate_Mask | kRectStaysRect_Mask);
       }
   }

這里我們看到實際上不當當進行了縮放操作,還進行了平移操作,所以我們實際進行縮放的時候,還伴隨著平移操作,實際上這里最后換算成的算法是fMat[kMTransX] = px - sx * px;。所以想要保持在縮放過程中不進行平移,那么我們需要改造一下算法px = fMat[kMTransX]/(1-sx),那么有人會問,那我怎么能提前知道fMat[kMTransX]的值呢,這里就要在每次縮放操作前,根據當前需要縮放的比例,預測量出值,這里就不介紹怎么預測量,相信機智的小伙伴肯定已經有想法了~好了,這里就講到這里,有問題請留言,我會及時回復,歡迎交流~

?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • CSDN博客 img cquwentao android matrix 最全方法詳解與進階(完整篇) 發(fā)表于201...
    北風知我意閱讀 5,130評論 0 0
  • 一、矩陣的定義 二、矩陣與矩陣的乘法 矩陣的乘法滿足以下運算律:結合律,分配律,但是矩陣乘法不滿足交換律。更詳細的...
    Calllanna閱讀 2,924評論 0 1
  • 1、引子 筆者剛開始工作時,做的第一個模塊是手機中的launcher,launcher可自由選擇滑屏效果,甚至還有...
    某昆閱讀 4,293評論 0 6
  • 本文行文目錄:一、Camera與Matrix初步認識二、Camera與Matrix旋轉效果拆分介紹三、Camera...
    zhangke3016閱讀 19,021評論 18 136
  • 1.早上看第五單元單詞視頻 2.去老師辦公室實習一天 *當你探測到未知領域的時候就會特別興奮,如果覺得還能學到東西...
    追咪閱讀 244評論 0 0

友情鏈接更多精彩內容