Android:手把手教你打造可縮放移動的ImageView(上)

定義ImageView,實現功能以下:java

1.初始化時圖片垂直居中顯示,拉伸圖片寬度至ImageView寬度。android

2.使用兩根手指放大縮小圖片,可設置最大放大倍數,當圖片小於ImageView寬度時,在手指離開屏幕時恢復到ImageView寬度。git

3.支持雙擊放大縮小。當圖片處於未放大狀態時,雙擊放大至指定倍數,當圖片處於放大狀態時,雙擊恢復至未放大狀態。github

4.圖片拖動效果。當圖片處於未放大狀態時,不可拖動。數組

5.圖片拖動效果。當放大後的高度不超過ImageView時,不可垂直拖動。(因爲默認設置拉伸寬度至ImageView寬度,水平方向可不判斷)。ide

6.圖片拖動效果。當圖片向右拖動時,若左邊緣超出左邊界,則中止水平拖動。同理上下右邊緣,即拖動後不會看到背景留白。函數

 

 

首先講一下原理,圖片放大縮小無非就是使用Matrix類,而這裏經過手勢控制,那天然是須要監聽onTouch事件,因此原理簡單來講,就是經過監聽onTouch的各類事件來控制Matrix類了。其中具體控制方式以下:post

onTouch Matrix 輔助操做
ACTION_DOWN 記錄初始點,設置本次模式爲拖動模式,ScaleType設置成Matrix
ACTION_POINTER_DOWN 設置本次模式爲縮放模式
ACTION_MOVE 根據模式執行postScale或postTranslate  
ACTION_UP 根據當前縮放級別決定是否重置Matrix  
雙擊 postScale  
ACTION_CANCEL 同UP  

 

 

 

 

 

 

如今開始,按功能點一一列代碼說明:this

首先自定義ImageView,因爲和Matrix有關,取名爲MatrixImageView.java,繼承於ImageView.javaspa

public class MatrixImageView extends ImageView{
    private final static String TAG="MatrixImageView";
    private GestureDetector mGestureDetector;
    /**  模板Matrix,用以初始化 */ 
    private  Matrix mMatrix=new Matrix();
    /**  圖片長度*/ 
    private float mImageWidth;
    /**  圖片高度 */ 
    private float mImageHeight;

    public MatrixImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        MatrixTouchListener mListener=new MatrixTouchListener();
        setOnTouchListener(mListener);
        mGestureDetector=new GestureDetector(getContext(), new GestureListener(mListener));
        //背景設置爲balck
        setBackgroundColor(Color.BLACK);
        //將縮放類型設置爲FIT_CENTER,表示把圖片按比例擴大/縮小到View的寬度,居中顯示
        setScaleType(ScaleType.FIT_CENTER);
    }

因爲用到了雙擊縮放效果,在此引用了手勢類 GestureDetector,GestureListener就是繼承與SimpleOnGestureListener的手勢監聽類了。MatrixTouchListener繼承與onTouchListner,是Touch事件監聽的主體。在構造函數最後一句setScaleType(ScaleType.FIT_CENTER),即是知足功能一的要點。

接下去,重寫setImageBitmap方法。

@Override
    public void setImageBitmap(Bitmap bm) {
        // TODO Auto-generated method stub
        super.setImageBitmap(bm);
        //設置完圖片後,獲取該圖片的座標變換矩陣
        mMatrix.set(getImageMatrix());
        float[] values=new float[9];
        mMatrix.getValues(values);
        //圖片寬度爲屏幕寬度除縮放倍數
        mImageWidth=getWidth()/values[Matrix.MSCALE_X];
        mImageHeight=(getHeight()-values[Matrix.MTRANS_Y]*2)/values[Matrix.MSCALE_Y];
    }

在此是爲了初始化幾個重要的變量:

mMatrix:圖片的原始Matrix,記錄下來做爲模板,以後的變化都是在這個Matrix的基礎上進行
mImageWidth:圖片的真實寬度,注意這個寬度是指圖片在ImageView中的真實寬度,非顯示寬度也非文件寬度。當咱們把圖片放入ImageView中時,會根據ImageView的寬高進行一個轉換,轉換結果記錄在Matrix中。咱們根據顯示寬度與Matrix進行計算得到真實寬度。
mImageHeight:同寬度。

三種寬度的區別(非官方叫法,只爲理解)

 

顯示寬度:ImageView中的圖片(Bitmap、Drawable)在ImageView中顯示的高度,是經過Matrix計算以後的寬度。當放大圖片時,這個寬度可能超過ImageView的寬度。
真實寬度:ImageView中的圖片在Matrix計算以前的寬度。當ImageView寬爲390,圖片X軸縮放級別爲0.5,一個填充滿ImageView的X軸的圖片的真實寬度爲780。這個寬度和ImageView的ScaleType相關。
文件寬度:文件X軸分辨率,不必定等於真實寬度。

 

之因此在sitImageView中進行設置,是由於每次ImageView更換圖片後這些變量都會跟着改變,咱們只須要和當前圖片相關的這些變量。若但願在layout中設置圖片而不是代碼中設置,請把上述代碼移至構造函數。

接下來是重點的onTouch事件:

public class MatrixTouchListener implements OnTouchListener{
        /** 拖拉照片模式 */
        private static final int MODE_DRAG = 1;
        /** 放大縮小照片模式 */
        private static final int MODE_ZOOM = 2;
        /**  不支持Matrix */ 
        private static final int MODE_UNABLE=3;
        /**   最大縮放級別*/ 
        float mMaxScale=6;
        /**   雙擊時的縮放級別*/ 
        float mDobleClickScale=2;
        private int mMode = 0;// 
        /**  縮放開始時的手指間距 */ 
        private float mStartDis;
        /**   當前Matrix*/ 
        private Matrix mCurrentMatrix = new Matrix();    

        /** 用於記錄開始時候的座標位置 */
        private PointF startPoint = new PointF();
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            // TODO Auto-generated method stub
            switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                //設置拖動模式
                mMode=MODE_DRAG;
                startPoint.set(event.getX(), event.getY());
               // isMatrixEnable();
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                reSetMatrix();
                break;
            case MotionEvent.ACTION_MOVE:
                if (mMode == MODE_ZOOM) {
                    setZoomMatrix(event);
                }else if (mMode==MODE_DRAG) {
                    setDragMatrix(event);
                }
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                if(mMode==MODE_UNABLE) return true;
                mMode=MODE_ZOOM;
                mStartDis = distance(event);
                break;
            default:
                break;
            }

            return mGestureDetector.onTouchEvent(event);
        }

/**  
         *  計算兩個手指間的距離
         *  @param event
         *  @return   
         */
        private float distance(MotionEvent event) {
            float dx = event.getX(1) - event.getX(0);
            float dy = event.getY(1) - event.getY(0);
            /** 使用勾股定理返回兩點之間的距離 */
            return (float) Math.sqrt(dx * dx + dy * dy);
        }

 

首先能夠看到,在ACTION_DOWN和ACTION_POINTER_DOWN中主要是進行當前事件模式的肯定。當咱們按下一個點時,會觸發Down事件,而按下第二個點後,又會觸發Action_Pointer_Down事件,在此咱們把按下一個點標記爲拖動事件,按下兩個點標記爲縮放事件。先跟蹤縮放事件方法setZoomMatrix(event);

/**  
         *  設置縮放Matrix
         *  @param event   
         */
        private void setZoomMatrix(MotionEvent event) {
            //只有同時觸屏兩個點的時候才執行
            if(event.getPointerCount()<2) return;
            float endDis = distance(event);// 結束距離
            if (endDis > 10f) { // 兩個手指併攏在一塊兒的時候像素大於10
                float scale = endDis / mStartDis;// 獲得縮放倍數
                mStartDis=endDis;//重置距離
                mCurrentMatrix.set(getImageMatrix());//初始化Matrix
                float[] values=new float[9];
                mCurrentMatrix.getValues(values);

                scale = checkMaxScale(scale, values);
                setImageMatrix(mCurrentMatrix);    
            }
        }

首先咱們判斷是否點擊了兩個點,若是不是直接返回。接着,使用distance方法計算出兩個點之間的距離。以前在Action_Pointer_Down中已經計算出了初始距離,這裏計算出的是移動後的兩個點的距離。經過這兩個距離咱們能夠得出本次移動的縮放倍數,但這還沒完,咱們須要驗證這個縮放倍數是否越界了:

/**  
         *  檢驗scale,使圖像縮放後不會超出最大倍數
         *  @param scale
         *  @param values
         *  @return   
         */
        private float checkMaxScale(float scale, float[] values) {
            if(scale*values[Matrix.MSCALE_X]>mMaxScale) 
                scale=mMaxScale/values[Matrix.MSCALE_X];
            mCurrentMatrix.postScale(scale, scale,getWidth()/2,getHeight()/2);
            return scale;
        }

咱們獲取了Matrix矩陣中保存的數組,在這個數組中,values[Matrix.MSCALE_X](事實上就是數組的第0個)表明了X軸的縮放級別,判斷一下圖片當前的縮放級別再乘以剛獲得的scale後是否回去越界,會的話就將其控制在邊界值。以後,以ImageView的中心點爲原點,在當前Matrix的基礎上進行指定倍數的縮放。

在Move事件中縮放時咱們只會阻止超越最大值的縮放,在UP事件中咱們會對小於原始縮放值的縮放進行重置。方法reSetMatrix以下。

/**  
         *   重置Matrix
         */
        private void reSetMatrix() {
            if(checkRest()){
                mCurrentMatrix.set(mMatrix);
                setImageMatrix(mCurrentMatrix);
            }
        }
/**  
         *  判斷是否須要重置
         *  @return  當前縮放級別小於模板縮放級別時,重置 
         */
        private boolean checkRest() {
            // TODO Auto-generated method stub
            float[] values=new float[9];
            getImageMatrix().getValues(values);
            //獲取當前X軸縮放級別
            float scale=values[Matrix.MSCALE_X];
            //獲取模板的X軸縮放級別,二者作比較
            mMatrix.getValues(values);
            return scale<values[Matrix.MSCALE_X];
        }

首先獲取當前X軸縮放級別(因爲默認拉伸寬度至ImageView寬度,縮放級別以X軸爲準),再經過模板Matrix獲得原始的X軸縮放級別,判斷當前縮放級別是否小於模板縮放級別,若小於,則重置成模板縮放級別。

接下去是雙擊放大縮小圖片效果,該功能在手勢接口GestureListener中完成,主要代碼以下:

    private class  GestureListener extends SimpleOnGestureListener{
        private final MatrixTouchListener listener;
        public GestureListener(MatrixTouchListener listener) {
            this.listener=listener;
        }
        @Override
        public boolean onDown(MotionEvent e) {
            //捕獲Down事件
            return true;
        }
        @Override
        public boolean onDoubleTap(MotionEvent e) {
            //觸發雙擊事件
            listener.onDoubleClick();
            return true;
        }
/**  
         *   雙擊時觸發
         */
        public void onDoubleClick(){
            float scale=isZoomChanged()?1:mDobleClickScale;
            mCurrentMatrix.set(mMatrix);//初始化Matrix
            mCurrentMatrix.postScale(scale, scale,getWidth()/2,getHeight()/2);    
            setImageMatrix(mCurrentMatrix);
        }
/**  
         *  判斷縮放級別是不是改變過
         *  @return   true表示非初始值,false表示初始值
         */
        private boolean isZoomChanged() {
            float[] values=new float[9];
            getImageMatrix().getValues(values);
            //獲取當前X軸縮放級別
            float scale=values[Matrix.MSCALE_X];
            //獲取模板的X軸縮放級別,二者作比較
            mMatrix.getValues(values);
            return scale!=values[Matrix.MSCALE_X];
        }

 

在構造函數中將onTouchListner傳遞來進來。在此只重寫兩個方法:Down和onDoubleTap,只有在Down事件中返回true,onDoubleTap才能正常觸發。

在onDoubleClick事件中,首先經過isZoomChanged方法判斷當前的縮放級別是不是模板Matrix的縮放級別,是的話將縮放倍數設置爲2倍,否的話設置成1倍。在載入模板Matrix,在此基礎上作縮放。

最後是圖片拖動效果setDragMatrix()

public void setDragMatrix(MotionEvent event) {
            if(isZoomChanged()){
                float dx = event.getX() - startPoint.x; // 獲得x軸的移動距離
                float dy = event.getY() - startPoint.y; // 獲得x軸的移動距離
                //避免和雙擊衝突,大於10f纔算是拖動
                if(Math.sqrt(dx*dx+dy*dy)>10f){
                    startPoint.set(event.getX(), event.getY());
                    //在當前基礎上移動
                    mCurrentMatrix.set(getImageMatrix());
                    float[] values=new float[9];
                    mCurrentMatrix.getValues(values);
                    dx=checkDxBound(values,dx);
                    dy=checkDyBound(values,dy);    
                    mCurrentMatrix.postTranslate(dx, dy);
                    setImageMatrix(mCurrentMatrix);
                }
            }
        }

首先是經過isZoomChanged方法判斷是否縮放過,若未縮放過則不可拖動(這種狀況下圖片全貌均可以看到,不須要拖動)。接着,拿當前座標和按下時記錄的startPoint座標進行計算,得出拖動的距離。須要注意的是,在此須要對拖動距離作一個判斷,當其小於10f時不進行拖動,不然會和雙擊事件衝突(在雙擊事件前一樣會觸發Move事件,二者一同執行的話,雙擊的縮放沒法正常工做)。當肯定開始拖動的以後,先重置startPoint的座標,接着,開始驗證當前移動的位移量是否合法。

/**  
         *和當前矩陣對比,檢驗dx,使圖像移動後不會超出ImageView邊界
         *  @param values
         *  @param dx
         *  @return   
         */
        private float checkDxBound(float[] values,float dx) {
            float width=getWidth();
            if(mImageWidth*values[Matrix.MSCALE_X]<width)
                return 0;
            if(values[Matrix.MTRANS_X]+dx>0)
                dx=-values[Matrix.MTRANS_X];
            else if(values[Matrix.MTRANS_X]+dx<-(mImageWidth*values[Matrix.MSCALE_X]-width))
                dx=-(mImageWidth*values[Matrix.MSCALE_X]-width)-values[Matrix.MTRANS_X];
            return dx;
        }

/**  
         *  和當前矩陣對比,檢驗dy,使圖像移動後不會超出ImageView邊界
         *  @param values
         *  @param dy
         *  @return   
         */
        private float checkDyBound(float[] values, float dy) {
            float height=getHeight();
            if(mImageHeight*values[Matrix.MSCALE_Y]<height)
                return 0;
            if(values[Matrix.MTRANS_Y]+dy>0)
                dy=-values[Matrix.MTRANS_Y];
            else if(values[Matrix.MTRANS_Y]+dy<-(mImageHeight*values[Matrix.MSCALE_Y]-height))
                dy=-(mImageHeight*values[Matrix.MSCALE_Y]-height)-values[Matrix.MTRANS_Y];
            return dy;
        }

以Y軸爲例,首先獲取ImageView高度,再經過sitImageBitmap方法中獲取的圖片真實高度和當前Y軸縮放級別計算出當前Y軸的顯示高度。若是顯示高度小於ImageView高度,表示當前顯示的圖片尚未ImageView高,在Y軸不須要移動均可看清全貌,Y軸位移量直接返回0。

假如顯示高度超過了ImageView高度,獲取圖片當前在Y軸的位移量(values[Matrix.MTRANS_Y]值),將其加上計算出的位移量後是否大於0,若大於0,表示圖片上邊緣將會離開ImageView上邊緣,須要從新計算位移量。若上述條件不成立,判斷當前位移量加上計算後的位移量,是否小於圖片顯示高度-屏幕高度,若小於表示圖片下邊緣將離開ImageView下邊緣,一樣須要從新計算。最後返回計算的Y軸偏移量。X軸同理。最後使用驗證過的X、Y軸偏移量,在當前圖片Matrix的基礎上行進行偏移。

最後貼下完整代碼,Demo的話,能夠到個人照相機Demo裏查看,該功能爲相冊功能的一部分。

package com.linj.album.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;

/** 
 * @ClassName: MatrixImageView 
 * @Description:  帶放大、縮小、移動效果的ImageView
 * @author LinJ
 * @date 2015-1-7 上午11:15:07 
 *  
 */
public class MatrixImageView extends ImageView{
    private final static String TAG="MatrixImageView";
    private GestureDetector mGestureDetector;
    /**  模板Matrix,用以初始化 */ 
    private  Matrix mMatrix=new Matrix();
    /**  圖片長度*/ 
    private float mImageWidth;
    /**  圖片高度 */ 
    private float mImageHeight;

    public MatrixImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        MatrixTouchListener mListener=new MatrixTouchListener();
        setOnTouchListener(mListener);
        mGestureDetector=new GestureDetector(getContext(), new GestureListener(mListener));
        //背景設置爲balck
        setBackgroundColor(Color.BLACK);
        //將縮放類型設置爲FIT_CENTER,表示把圖片按比例擴大/縮小到View的寬度,居中顯示
        setScaleType(ScaleType.FIT_CENTER);
    }

    @Override
    public void setImageBitmap(Bitmap bm) {
        // TODO Auto-generated method stub
        super.setImageBitmap(bm);
        //設置完圖片後,獲取該圖片的座標變換矩陣
        mMatrix.set(getImageMatrix());
        float[] values=new float[9];
        mMatrix.getValues(values);
        //圖片寬度爲屏幕寬度除縮放倍數
        mImageWidth=getWidth()/values[Matrix.MSCALE_X];
        mImageHeight=(getHeight()-values[Matrix.MTRANS_Y]*2)/values[Matrix.MSCALE_Y];
    }

    public class MatrixTouchListener implements OnTouchListener{
        /** 拖拉照片模式 */
        private static final int MODE_DRAG = 1;
        /** 放大縮小照片模式 */
        private static final int MODE_ZOOM = 2;
        /**  不支持Matrix */ 
        private static final int MODE_UNABLE=3;
        /**   最大縮放級別*/ 
        float mMaxScale=6;
        /**   雙擊時的縮放級別*/ 
        float mDobleClickScale=2;
        private int mMode = 0;// 
        /**  縮放開始時的手指間距 */ 
        private float mStartDis;
        /**   當前Matrix*/ 
        private Matrix mCurrentMatrix = new Matrix();    

        /** 用於記錄開始時候的座標位置 */
        private PointF startPoint = new PointF();
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            // TODO Auto-generated method stub
            switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                //設置拖動模式
                mMode=MODE_DRAG;
                startPoint.set(event.getX(), event.getY());
                isMatrixEnable();
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                reSetMatrix();
                break;
            case MotionEvent.ACTION_MOVE:
                if (mMode == MODE_ZOOM) {
                    setZoomMatrix(event);
                }else if (mMode==MODE_DRAG) {
                    setDragMatrix(event);
                }
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                if(mMode==MODE_UNABLE) return true;
                mMode=MODE_ZOOM;
                mStartDis = distance(event);
                break;
            default:
                break;
            }

            return mGestureDetector.onTouchEvent(event);
        }

        public void setDragMatrix(MotionEvent event) {
            if(isZoomChanged()){
                float dx = event.getX() - startPoint.x; // 獲得x軸的移動距離
                float dy = event.getY() - startPoint.y; // 獲得x軸的移動距離
                //避免和雙擊衝突,大於10f纔算是拖動
                if(Math.sqrt(dx*dx+dy*dy)>10f){
                    startPoint.set(event.getX(), event.getY());
                    //在當前基礎上移動
                    mCurrentMatrix.set(getImageMatrix());
                    float[] values=new float[9];
                    mCurrentMatrix.getValues(values);
                    dx=checkDxBound(values,dx);
                    dy=checkDyBound(values,dy);    
                    mCurrentMatrix.postTranslate(dx, dy);
                    setImageMatrix(mCurrentMatrix);
                }
            }
        }

        /**  
         *  判斷縮放級別是不是改變過
         *  @return   true表示非初始值,false表示初始值
         */
        private boolean isZoomChanged() {
            float[] values=new float[9];
            getImageMatrix().getValues(values);
            //獲取當前X軸縮放級別
            float scale=values[Matrix.MSCALE_X];
            //獲取模板的X軸縮放級別,二者作比較
            mMatrix.getValues(values);
            return scale!=values[Matrix.MSCALE_X];
        }

        /**  
         *  和當前矩陣對比,檢驗dy,使圖像移動後不會超出ImageView邊界
         *  @param values
         *  @param dy
         *  @return   
         */
        private float checkDyBound(float[] values, float dy) {
            float height=getHeight();
            if(mImageHeight*values[Matrix.MSCALE_Y]<height)
                return 0;
            if(values[Matrix.MTRANS_Y]+dy>0)
                dy=-values[Matrix.MTRANS_Y];
            else if(values[Matrix.MTRANS_Y]+dy<-(mImageHeight*values[Matrix.MSCALE_Y]-height))
                dy=-(mImageHeight*values[Matrix.MSCALE_Y]-height)-values[Matrix.MTRANS_Y];
            return dy;
        }

        /**  
         *和當前矩陣對比,檢驗dx,使圖像移動後不會超出ImageView邊界
         *  @param values
         *  @param dx
         *  @return   
         */
        private float checkDxBound(float[] values,float dx) {
            float width=getWidth();
            if(mImageWidth*values[Matrix.MSCALE_X]<width)
                return 0;
            if(values[Matrix.MTRANS_X]+dx>0)
                dx=-values[Matrix.MTRANS_X];
            else if(values[Matrix.MTRANS_X]+dx<-(mImageWidth*values[Matrix.MSCALE_X]-width))
                dx=-(mImageWidth*values[Matrix.MSCALE_X]-width)-values[Matrix.MTRANS_X];
            return dx;
        }

        /**  
         *  設置縮放Matrix
         *  @param event   
         */
        private void setZoomMatrix(MotionEvent event) {
            //只有同時觸屏兩個點的時候才執行
            if(event.getPointerCount()<2) return;
            float endDis = distance(event);// 結束距離
            if (endDis > 10f) { // 兩個手指併攏在一塊兒的時候像素大於10
                float scale = endDis / mStartDis;// 獲得縮放倍數
                mStartDis=endDis;//重置距離
                mCurrentMatrix.set(getImageMatrix());//初始化Matrix
                float[] values=new float[9];
                mCurrentMatrix.getValues(values);

                scale = checkMaxScale(scale, values);
                setImageMatrix(mCurrentMatrix);    
            }
        }

        /**  
         *  檢驗scale,使圖像縮放後不會超出最大倍數
         *  @param scale
         *  @param values
         *  @return   
         */
        private float checkMaxScale(float scale, float[] values) {
            if(scale*values[Matrix.MSCALE_X]>mMaxScale) 
                scale=mMaxScale/values[Matrix.MSCALE_X];
            mCurrentMatrix.postScale(scale, scale,getWidth()/2,getHeight()/2);
            return scale;
        }

        /**  
         *   重置Matrix
         */
        private void reSetMatrix() {
            if(checkRest()){
                mCurrentMatrix.set(mMatrix);
                setImageMatrix(mCurrentMatrix);
            }
        }

        /**  
         *  判斷是否須要重置
         *  @return  當前縮放級別小於模板縮放級別時,重置 
         */
        private boolean checkRest() {
            // TODO Auto-generated method stub
            float[] values=new float[9];
            getImageMatrix().getValues(values);
            //獲取當前X軸縮放級別
            float scale=values[Matrix.MSCALE_X];
            //獲取模板的X軸縮放級別,二者作比較
            mMatrix.getValues(values);
            return scale<values[Matrix.MSCALE_X];
        }

        /**  
         *  判斷是否支持Matrix
         */
        private void isMatrixEnable() {
            //當加載出錯時,不可縮放
            if(getScaleType()!=ScaleType.CENTER){
                setScaleType(ScaleType.MATRIX);
            }else {
                mMode=MODE_UNABLE;//設置爲不支持手勢
            }
        }

        /**  
         *  計算兩個手指間的距離
         *  @param event
         *  @return   
         */
        private float distance(MotionEvent event) {
            float dx = event.getX(1) - event.getX(0);
            float dy = event.getY(1) - event.getY(0);
            /** 使用勾股定理返回兩點之間的距離 */
            return (float) Math.sqrt(dx * dx + dy * dy);
        }

        /**  
         *   雙擊時觸發
         */
        public void onDoubleClick(){
            float scale=isZoomChanged()?1:mDobleClickScale;
            mCurrentMatrix.set(mMatrix);//初始化Matrix
            mCurrentMatrix.postScale(scale, scale,getWidth()/2,getHeight()/2);    
            setImageMatrix(mCurrentMatrix);
        }
    }


    private class  GestureListener extends SimpleOnGestureListener{
        private final MatrixTouchListener listener;
        public GestureListener(MatrixTouchListener listener) {
            this.listener=listener;
        }
        @Override
        public boolean onDown(MotionEvent e) {
            //捕獲Down事件
            return true;
        }
        @Override
        public boolean onDoubleTap(MotionEvent e) {
            //觸發雙擊事件
            listener.onDoubleClick();
            return true;
        }
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            // TODO Auto-generated method stub
            return super.onSingleTapUp(e);
        }

        @Override
        public void onLongPress(MotionEvent e) {
            // TODO Auto-generated method stub
            super.onLongPress(e);
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2,
                float distanceX, float distanceY) {
            return super.onScroll(e1, e2, distanceX, distanceY);
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                float velocityY) {
            // TODO Auto-generated method stub

            return super.onFling(e1, e2, velocityX, velocityY);
        }

        @Override
        public void onShowPress(MotionEvent e) {
            // TODO Auto-generated method stub
            super.onShowPress(e);
        }

        

        

        @Override
        public boolean onDoubleTapEvent(MotionEvent e) {
            // TODO Auto-generated method stub
            return super.onDoubleTapEvent(e);
        }

        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            // TODO Auto-generated method stub
            return super.onSingleTapConfirmed(e);
        }

    }


}

注:當該ImageView在其餘ViewGroup中,如經常使用的ViewPager中時,Move事件會和ViewGroup事件衝突。在劃屏進行ViewPager的Item切換時,Viewpager將會經過onInterceptTouchEvent方法攔截掉,返回給ImageView一個Cancel事件,這種狀況下須要重寫ViewGroup的onInterceptTouchEvent方法。

相關文章
相關標籤/搜索