1. 程式人生 > >圖片的預覽處理----多點觸控放縮/雙擊放大縮小/viewPager衝突解決

圖片的預覽處理----多點觸控放縮/雙擊放大縮小/viewPager衝突解決

在android中,多點觸控和雙擊圖片很常用,比如朋友圈點選圖片放大兼具手勢點選滑動等;當然也有不少第三方來支援這些 比如:phtotView等;

下面來實現一個自己實現的多點操作的圖片預覽,老規矩 先上圖來展示效果:

這裡寫圖片描述

由於是擷取模擬器的gif 所以沒有顯示多點觸控 的手勢操作 但是手機上完全支援這些操作:

    1.手勢多點放縮,且會有最大和最小的限制;
    2.雙擊放大縮小
    3.在放大時候可以滑動來全覽圖片
    4.支援viewPager的滑動,切不會和圖片放縮衝突

下面從程式碼角度來剖析demo:

1.初始化操作,最優展示圖片:

MainActiivty和Viewpager的Adapter程式碼 不做展示;最後會全部展示程式碼;直接來看自定義的圖片類:
初始化ZoomImageView:

public class ZoomImageView extends ImageView implements ViewTreeObserver.OnGlobalLayoutListener {

    private boolean mOnce;
    private float minScale;
    private float maxScale;
    private float mTouchScale;
    private Matrix mMatrix;


    public ZoomImageView(Context context) {
        this
(context,null); } public ZoomImageView(Context context, @Nullable AttributeSet attrs) { this(context, attrs,0); } public ZoomImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private
void init() { mMatrix = new Matrix(); setScaleType(ScaleType.MATRIX); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); //註冊監聽 繪製完成設定圖片 getViewTreeObserver().addOnGlobalLayoutListener(this); } @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN) @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); getViewTreeObserver().removeOnGlobalLayoutListener(this); } @Override public void onGlobalLayout() { if (!mOnce){ float scale = 1; //獲取控制元件的寬和高 int width = getWidth(); int height = getHeight(); //獲取圖片 及其寬和高 Drawable drawable = getDrawable(); if (drawable == null) return; int intrinsicWidth = drawable.getIntrinsicWidth(); int intrinsicHeight = drawable.getIntrinsicHeight(); //控制元件的寬高和img比較確定縮放的比例 if (intrinsicWidth > width && intrinsicHeight < height){ scale = width * 1.0f / intrinsicWidth; } if (intrinsicHeight > height && intrinsicWidth < width){ scale = height * 1.0f / intrinsicHeight; } if ((intrinsicHeight > height && intrinsicWidth > width) || (intrinsicHeight < height && intrinsicWidth < width)){ scale = Math.min(height * 1.0f / intrinsicHeight ,width * 1.0f / intrinsicWidth); } minScale = scale; maxScale = 4 * minScale; mTouchScale = 2 * minScale; float dx = width/2 - intrinsicWidth/2; float dy = height/2 - intrinsicHeight/2; mMatrix.postTranslate(dx,dy); mMatrix.postScale(minScale,minScale,width/2,height/2); setImageMatrix(mMatrix); mOnce =true; } }

在 初始化中初始化了minScale,maxScale以及mMatrix等,需要注意的是 ,由於圖片width和height與screen不一定適配 所以需要程式碼進行優化,由於自定義view繪製有流程所以這裡用到:

   @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        //註冊監聽 繪製完成設定圖片
        getViewTreeObserver().addOnGlobalLayoutListener(this);
    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        getViewTreeObserver().removeOnGlobalLayoutListener(this);

    }

在view繫結window時候註冊監聽,繪製完成在onGlobalLayout中設定圖片;核心程式碼就是此處的監聽

getViewTreeObserver().addOnGlobalLayoutListener(this);
 @Override
    public void onGlobalLayout() {

        if (!mOnce){
            float scale = 1;
            //獲取控制元件的寬和高
            int width = getWidth();
            int height = getHeight();
            //獲取圖片 及其寬和高
            Drawable drawable = getDrawable();
            if (drawable == null)
                return;
            int intrinsicWidth = drawable.getIntrinsicWidth();
            int intrinsicHeight = drawable.getIntrinsicHeight();

            //控制元件的寬高和img比較確定縮放的比例
            if (intrinsicWidth > width && intrinsicHeight < height){
                scale = width * 1.0f / intrinsicWidth;
            }
            if (intrinsicHeight > height && intrinsicWidth < width){
                scale = height * 1.0f / intrinsicHeight;
            }
            if ((intrinsicHeight > height && intrinsicWidth > width) || (intrinsicHeight < height && intrinsicWidth < width)){
                scale =  Math.min(height * 1.0f / intrinsicHeight ,width * 1.0f / intrinsicWidth);
            }

            minScale = scale;
            maxScale = 4 * minScale;
            mTouchScale = 2 * minScale;
            float dx = width/2 - intrinsicWidth/2;
            float dy = height/2 - intrinsicHeight/2;
            mMatrix.postTranslate(dx,dy);
            mMatrix.postScale(minScale,minScale,width/2,height/2);

            setImageMatrix(mMatrix);




            mOnce =true;
        }
    }

在上面程式碼中回獲取圖片的寬和高,以及空間本身(就是自定義imageView在xml)中的寬和高進行對比,然後確定合適的比例來確定圖片的最優化縮放
到這裡,圖片無論小還是大都可以以最優的方案 展示;

2.多點觸控放縮圖片

接下來開始對圖片的多點觸控放大縮小進行處理:
這裡用到一個多點觸控的類ScaleGestureDetector;然後再init()中宣告這個類;

mScaleGestureDetector = new ScaleGestureDetector(getContext(), this);

然後自定義件的主類繼承介面ScaleGestureDetector.OnScaleGestureListener;
然後實現其中3個方法;

    //放縮過程中
    @Override
    public boolean onScale(ScaleGestureDetector scaleGestureDetector) {

        return true;}

    //放縮開始時候
    @Override
    public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
        return true;
    }


    //放縮結束時候
    @Override
    public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) {

    }

在onScale中進行多點觸控的邏輯處理:

    //放縮過程中
    @Override
    public boolean onScale(ScaleGestureDetector scaleGestureDetector) {

        float scale = getScale();
        float scaleFactor = scaleGestureDetector.getScaleFactor();

        //判斷drawable是否為空
        if (getDrawable() == null)
            return true;
        //判斷範圍
        if ((scale < maxScale && scale >= 1.0f) || (scale > minScale && scale <= 1.0f)){

            if (scale * scaleFactor > maxScale){
                    scaleFactor = maxScale/scale;
                }
            if (scale * scaleFactor < minScale){
                    scaleFactor = minScale/scale;
                }
        }
        /**
         * 限定圖片放縮的最大值和最小值
         * */
        else if (scale >= maxScale && scaleFactor > 1.0f){
            scaleFactor = maxScale/scale;
        }else if (scale <= minScale/2 && scaleFactor < 1.0f){

            scaleFactor = minScale/(2*scale);
        }


        //注意這裡要以手勢中心為縮放中心
        mMatrix.postScale(scaleFactor,scaleFactor,
                scaleGestureDetector.getFocusX(),scaleGestureDetector.getFocusY());

        transBoderAndCenter();

        setImageMatrix(mMatrix);

        return true;
    }

首先獲取當前的scale:

private float getScale() {
        float[] values = new float[9];
        mMatrix.getValues(values);
        float value = values[Matrix.MSCALE_X];
        return value;
    }

通過scale與1.0f的比較進行放大和縮小的判斷;當scale>1.0f 時候為放大 ,反之為縮小;然後對最大和最小進行限制:

/**
         * 限定圖片放縮的最大值和最小值
         * */
        else if (scale >= maxScale && scaleFactor > 1.0f){
            scaleFactor = maxScale/scale;
        }else if (scale <= minScale/2 && scaleFactor < 1.0f){
            //Log.i("==scale",String.valueOf(scaleFactor));
            scaleFactor = minScale/(2*scale);
        }

最後利用mMatrix對圖片進行放縮:

 //注意這裡要以手勢中心為縮放中心
        mMatrix.postScale(scaleFactor,scaleFactor,
                scaleGestureDetector.getFocusX(),scaleGestureDetector.getFocusY());

        transBoderAndCenter();

        setImageMatrix(mMatrix);

在程式碼中有主意到在真正傳參設定之前,有一個方法:transBoderAndCenter():


    //在縮放時候進行邊界控制和中心點的控制
    private void transBoderAndCenter() {
        //設定x和y的邊界值
        float Dx = 0;
        float Dy = 0;
        RectF rectF = getRectF();
        int width = getWidth();
        int height = getHeight();

        float l = rectF.left;
        float r = rectF.right;
        float t = rectF.top;
        float b = rectF.bottom;


        float w = rectF.width();
        float h = rectF.height();

        if (w >= width){
            if (l > 0){
                Dx = -l;
            }
            if (r < width){
                Dx = width - r;
            }
        }

        if (h >= height){
            if (t > 0){
                Dy = -t;
            }
            if (b < height){
                Dy = height - b;
            }
        }

        if (w < width){
            Dx = width/2 - r + w/2;
        }
        if (h < height){
            Dy = height/2 - b + h/2;
        }

        mMatrix.postTranslate(Dx,Dy);


    }

是為了防止在放縮過程中會有空白邊界產生;

3.處理放大之後的圖片滑動:

在放大之後全屏無法展示圖片,所以會有圖片滑動預覽的操作;自然要實現自定義控制元件的onTouch事件:
在init()中註冊監聽 類繼承touch的介面View.OnTouchListener並且初始化滑動的有效距離mTouchslop:

setOnTouchListener(this);
mTouchslop = ViewConfiguration.get(getContext()).getScaledTouchSlop();

ok~ 直接上核心程式碼:

 @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {


        mScaleGestureDetector.onTouchEvent(motionEvent);

        /**-------------------------------------------
         * 設定自由移動*/

        float x = 0;
        float y = 0;

        int pointerCount = motionEvent.getPointerCount();
        for (int i = 0; i < pointerCount; i++) {
            x += motionEvent.getX(i);
            y += motionEvent.getY(i);
        }

        x /= pointerCount;
        y /= pointerCount;


        if (mPointCount != pointerCount){
            mLastX = x;
            mLastY = y;
            isMove = false;
        }

        mPointCount = pointerCount;

        RectF rect = getRectF();





            case MotionEvent.ACTION_MOVE:
                isMoveX = true;
                isMoveY = true;
                float mx = 0;
                float my = 0;

                int count = motionEvent.getPointerCount();
                for (int i = 0; i < count; i++) {
                    mx += motionEvent.getX(i);
                    my += motionEvent.getY(i);
                }
                    mx /= count;
                    my /= count;
                float dx = mx - mLastX;
                float dy = my - mLastY;
                if (!isMove){
                   isMove = isMoveZoom(dx, dy);
                }

                if (isMove){
                    RectF rectF = getRectF();
                    float w = rectF.width();
                    float h = rectF.height();
                    int width = getWidth();
                    int height = getHeight();

                    if (getDrawable() != null){
                        if (w < width){
                            isMoveX = false;
                            dx = 0;
                        }
                        if (h < height){
                            isMoveY = false;
                            dy = 0;
                        }
                        mMatrix.postTranslate(dx,dy);
                        transBoder();
                        setImageMatrix(mMatrix);
                    }
                }
                mLastX = x;
                mLastY = y
            }

                break;

            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                mPointCount = 0;
                break;
        }
        return true;
    }

由於在滑動過程中也是多點觸控,所以不能直接監聽滑動的x.y;需要計算中心點:


        int pointerCount = motionEvent.getPointerCount();
        for (int i = 0; i < pointerCount; i++) {
            x += motionEvent.getX(i);
            y += motionEvent.getY(i);
        }

        x /= pointerCount;
        y /= pointerCount;


        if (mPointCount != pointerCount){
            mLastX = x;
            mLastY = y;
            isMove = false;
        }

在滑動過程中,若圖片縮小為寬和高均小於srceen的寬和高,則不能滑動;位移變數dx= 0;dy = 0:

    if (w < width){
                            isMoveX = false;
                            dx = 0;
                        }
                        if (h < height){
                            isMoveY = false;
                            dy = 0;
                        }

除此之外均可以滑動,而且 在滑動過程中要加限制 不然會出現無限滑動,最後設定mMatrix完成滑動的事件:

        transBoder();
        setImageMatrix(mMatrix);
        .....
        .....
private void transBoder() {
        //設定x和y的邊界值
        float Dx = 0;
        float Dy = 0;
        RectF rectF = getRectF();
        int width = getWidth();
        int height = getHeight();

        float l = rectF.left;
        float r = rectF.right;
        float t = rectF.top;
        float b = rectF.bottom;


        float w = rectF.width();
        float h = rectF.height();

        if (l > 0 && isMoveX){
            Dx = -l;
        }
        if (r < width && isMoveX){
            Dx = width - r;
        }

        if (t > 0 && isMoveY){
            Dy = -t;
        }
        if (b < height && isMoveY){
            Dy = height - b;
        }

        mMatrix.postTranslate(Dx,Dy);
    }

    private boolean isMoveZoom(float dx, float dy) {
        return Math.sqrt(dx * dx + dy * dy) > mTouchslop;
    }

4雙擊放縮的處理

雙擊要用到GestureDetector;首先在onTouch中改變return的boolean,防止點選時候滑動:

   if (mGes.onTouchEvent(motionEvent)){
            return true;
        }

同樣可以通過實現介面來實現;但是介面中方法實現複寫的量太多,比較基類所以在init()中實現他的一個子類:

        mGes = new GestureDetector(getContext(),new GestureDetector.SimpleOnGestureListener(){
            @Override
            public boolean onDoubleTap(MotionEvent e) {
                float x = e.getX();
                float y = e.getY();
                float scale = getScale();

                if (scale < mTouchScale){

                    //放大的邏輯---注意要漸變
                    if (!isClick){
                        isClick = true;
                        postDelayed(new ChangeRunnable(mTouchScale,x,y),16);
                    }

                }else {

                    if (!isClick){
                        isClick = true;
                        //縮小的邏輯---注意要漸變
                        postDelayed(new ChangeRunnable(minScale,x,y),16);
                    }



                }


                return true;
            }
        });

同樣通過getScale來獲取當前的scale,通過scale來控制放大和縮小(以上程式碼邏輯一目瞭然);但是這樣的放大縮小比較迅速所以要想提高互動需要設定執行緒來控制放縮的梯度來給雙擊放縮帶來一個緩衝:

 public class ChangeRunnable implements Runnable{

        //目標值
        private float mTargetScale;
        //放縮的中心
        private float x;
        private float y;
        //放縮的梯度
        private float mTemp;
        private final float UP = 1.1f;
        private final float DOWN = 0.6f;

        public ChangeRunnable(float mTargetScale,float x,float y) {
            this.mTargetScale = mTargetScale;
            this.x = x;
            this.y = y;
            float scale = getScale();
            if (scale < mTargetScale){
                mTemp = UP;
            }
            if (scale > mTargetScale){
                mTemp = DOWN;
            }
        }

        @Override
        public void run() {
            if (!isClick)
                return;


            float currScale = getScale();

            if ((mTemp > 1.0f && currScale < mTargetScale) || (mTemp < 1.0f && currScale > mTargetScale)){
                //scale是在原圖基礎上來計算的
                mMatrix.postScale(mTemp,mTemp,x,y);
                transBoderAndCenter();
                setImageMatrix(mMatrix);

                postDelayed(this,16);
            }else if ((mTemp > 1.0f && currScale >= mTargetScale) || (mTemp < 1.0f && currScale <= mTargetScale)){
                mMatrix.postScale(mTargetScale/currScale,mTargetScale/currScale,x,y);
                transBoderAndCenter();
                setImageMatrix(mMatrix);

                isClick = false;
            }




        }
    }

這樣雙擊放縮的功能也已經完成了;

5.設定viewPager滑動,並且解決滑動衝突:

viewPager在xml中的新增和setAdapter比較常見沒有什麼問題,那麼我們直接來看滑動事件的衝突解決;
在onTouch中通過判斷圖片寬高和screen的對比來控制父類的攔截;即當圖片款或著高大於screen的時候請求父類不攔截:

switch (motionEvent.getAction()){
            case MotionEvent.ACTION_DOWN:

                if (rect.width() > getWidth()){
                    if (getParent() instanceof ViewPager){
                        //請求父類不攔截
                        getParent().requestDisallowInterceptTouchEvent(true);
                    }
                }

                break;


            case MotionEvent.ACTION_MOVE:


                if (rect.width() > getWidth()){
                    if (getParent() instanceof ViewPager){
                        //請求父類不攔截
                        getParent().requestDisallowInterceptTouchEvent(true);
                    }

這樣多點觸控放縮兼具滑動和雙擊放縮,以及流暢viewpager滑動的圖片預覽就大功告成了;

6完整程式碼

//MainActivity

package com.example.customimg;

import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;

import com.example.customimg.adapter.MyAdpter;

public class MainActivity extends AppCompatActivity {

    private ViewPager mViewPager;
    //初始化圖片集合
    private int[] mResId = new int[]{R.drawable.img_1,R.drawable.img_2,R.drawable.img_3};
    //初始化iv集合
    private ImageView[] mIvs = new ImageView[mResId.length];

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();
        initEvent();
    }

    private void initView() {
        mViewPager = (ViewPager) findViewById(R.id.viewPager);
    }

    private void initEvent() {
        mViewPager.setAdapter(new MyAdpter(this,mResId,mIvs));


    }
}

//ZoomImageView

package com.example.customimg.widget;

import android.content.Context;
import android.content.Loader;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewTreeObserver;
import android.widget.ImageView;


/**
 * Created by houruixiang on 2017/8/22.
 */

public class ZoomImageView extends ImageView implements ViewTreeObserver.OnGlobalLayoutListener
        ,View.OnTouchListener, ScaleGestureDetector.OnScaleGestureListener {

    private boolean mOnce;
    private float minScale;
    private float maxScale;
    private float mTouchScale;
    private Matrix mMatrix;
    /**捕獲多指觸控的手勢*/
    private ScaleGestureDetector mScaleGestureDetector;
    private Object rectF;



    /**------------------------------------------------
     * 自由移動*/
    private float mLastX;
    private float mLastY;

    private boolean isMoveX;
    private boolean isMoveY;

    private boolean isMove;

    private int mPointCount;
    private int mTouchslop;



    /**------------------------------------------------
     * 雙擊放大+縮小*/
    private GestureDetector mGes;
    private boolean isClick;

    public ZoomImageView(Context context) {
        this(context,null);
    }

    public ZoomImageView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public ZoomImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {


        mMatrix = new Matrix();
        setScaleType(ScaleType.MATRIX);
        mScaleGestureDetector = new ScaleGestureDetector(getContext(), this);
        setOnTouchListener(this);
        mTouchslop = ViewConfiguration.get(getContext()).getScaledTouchSlop();

        mGes = new GestureDetector(getContext(),new GestureDetector.SimpleOnGestureListener(){
            @Override
            public boolean onDoubleTap(MotionEvent e) {
                float x = e.getX();
                float y = e.getY();
                float scale = getScale();

                if (scale < mTouchScale){

                    Log.i("==currScale",String.valueOf(mTouchScale) + ":::" + String.valueOf(scale));
                    //放大的邏輯---注意要漸變
                    if (!isClick){
                        isClick = true;
                        postDelayed(new ChangeRunnable(mTouchScale,x,y),16);
                    }

                }else {

                    Log.i("==currScale2",String.valueOf(minScale) + ":::" + String.valueOf(scale));
                    if (!isClick){
                        isClick = true;
                        //縮小的邏輯---注意要漸變
                        postDelayed(new ChangeRunnable(minScale,x,y),16);
                    }



                }


                return true;
            }
        });

    }

    public class ChangeRunnable implements Runnable{

        //目標值
        private float mTargetScale;
        //放縮的中心
        private float x;
        private float y;
        //放縮的梯度
        private float mTemp;
        private final float UP = 1.1f;
        private final float DOWN = 0.6f;

        public ChangeRunnable(float mTargetScale,float x,float y) {
            this.mTargetScale = mTargetScale;
            this.x = x;
            this.y = y;
            float scale = getScale();
            if (scale < mTargetScale){
                mTemp = UP;
            }
            if (scale > mTargetScale){
                mTemp = DOWN;
            }
        }

        @Override
        public void run() {
            if (!isClick)
                return;


            float currScale = getScale();

            if ((mTemp > 1.0f && currScale < mTargetScale) || (mTemp < 1.0f && currScale > mTargetScale)){
                //scale是在原圖基礎上來計算的
                mMatrix.postScale(mTemp,mTemp,x,y);
                transBoderAndCenter();
                setImageMatrix(mMatrix);

                postDelayed(this,16);
            }else if ((mTemp > 1.0f && currScale >= mTargetScale) || (mTemp < 1.0f && currScale <= mTargetScale)){
                mMatrix.postScale(mTargetScale/currScale,mTargetScale/currScale,x,y);
                transBoderAndCenter();
                setImageMatrix(mMatrix);

                isClick = false;
            }




        }
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        //註冊監聽 繪製完成設定圖片
        getViewTreeObserver().addOnGlobalLayoutListener(this);
    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        getViewTreeObserver().removeOnGlobalLayoutListener(this);

    }

    @Override
    public void onGlobalLayout() {

        if (!mOnce){
            float scale = 1;
            //獲取控制元件的寬和高
            int width = getWidth();
            int height = getHeight();
            //獲取圖片 及其寬和高
            Drawable drawable = getDrawable();
            if (drawable == null)
                return;
            int intrinsicWidth = drawable.getIntrinsicWidth();
            int intrinsicHeight = drawable.getIntrinsicHeight();

            //控制元件的寬高和img比較確定縮放的比例
            if (intrinsicWidth > width && intrinsicHeight < height){
                scale = width * 1.0f / intrinsicWidth;
            }
            if (intrinsicHeight > height && intrinsicWidth < width){
                scale = height * 1.0f / intrinsicHeight;
            }
            if ((intrinsicHeight > height && intrinsicWidth > width) || (intrinsicHeight < height && intrinsicWidth < width)){
                scale =  Math.min(height * 1.0f / intrinsicHeight ,width * 1.0f / intrinsicWidth);
            }

            minScale = scale;
            maxScale = 4 * minScale;
            mTouchScale = 2 * minScale;
            float dx = width/2 - intrinsicWidth/2;
            float dy = height/2 - intrinsicHeight/2;
            mMatrix.postTranslate(dx,dy);
            mMatrix.postScale(minScale,minScale,width/2,height/2);

            setImageMatrix(mMatrix);




            mOnce =true;
        }
    }

    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {


        if (mGes.onTouchEvent(motionEvent)){
            return true;
        }

        mScaleGestureDetector.onTouchEvent(motionEvent);

        /**-------------------------------------------
         * 設定自由移動*/

        float x = 0;
        float y = 0;

        int pointerCount = motionEvent.getPointerCount();
        for (int i = 0; i < pointerCount; i++) {
            x += motionEvent.getX(i);
            y += motionEvent.getY(i);
        }

        x /= pointerCount;
        y /= pointerCount;


        if (mPointCount != pointerCount){
            mLastX = x;
            mLastY = y;
            isMove = false;
        }

        mPointCount = pointerCount;

        RectF rect = getRectF();


        switch (motionEvent.getAction()){
            case MotionEvent.ACTION_DOWN:

                if (rect.width() > getWidth()){
                    if (getParent() instanceof ViewPager){
                        //請求父類不攔截
                        getParent().requestDisallowInterceptTouchEvent(true);
                    }
                }

                break;


            case MotionEvent.ACTION_MOVE:


                if (rect.width() > getWidth()){
                    if (getParent() instanceof ViewPager){
                        //請求父類不攔截
                        getParent().requestDisallowInterceptTouchEvent(true);
                    }

                isMoveX = true;
                isMoveY = true;
                float mx = 0;
                float my = 0;


                int count = motionEvent.getPointerCount();
                for (int i = 0; i < count; i++) {
                    mx += motionEvent.getX(i);
                    my += motionEvent.getY(i);
                }
                    mx /= count;
                    my /= count;
                float dx = mx - mLastX;
                float dy = my - mLastY;


                if (!isMove){
                   isMove = isMoveZoom(dx, dy);
                }

                if (isMove){
                    RectF rectF = getRectF();
                    float w = rectF.width();
                    float h = rectF.height();
                    int width = getWidth();
                    int height = getHeight();

                    if (getDrawable() != null){
                        if (w < width){
                            isMoveX = false;
                            dx = 0;
                        }
                        if (h < height){
                            isMoveY = false;
                            dy = 0;
                        }
                        mMatrix.postTranslate(dx,dy);

                        transBoder();
                        setImageMatrix(mMatrix);
                    }

                }

                mLastX = x;
                mLastY = y;

            }

                break;

            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                mPointCount = 0;
                break;
        }


        //這不會攔截麼?
        return true;
    }

    private void transBoder() {
        //設定x和y的邊界值
        float Dx = 0;
        float Dy = 0;
        RectF rectF = getRectF();
        int width = getWidth();
        int height = getHeight();

        float l = rectF.left;
        float r = rectF.right;
        float t = rectF.top;
        float b = rectF.bottom;


        float w = rectF.width();
        float h = rectF.height();

        if (l > 0 && isMoveX){
            Dx = -l;
        }
        if (r < width && isMoveX){
            Dx = width - r;
        }

        if (t > 0 && isMoveY){
            Dy = -t;
        }
        if (b < height && isMoveY){
            Dy = height - b;
        }

        mMatrix.postTranslate(Dx,Dy);
    }

    private boolean isMoveZoom(float dx, float dy) {
        return Math.sqrt(dx * dx + dy * dy) > mTouchslop;
    }


    //放縮過程中
    @Override
    public boolean onScale(ScaleGestureDetector scaleGestureDetector) {

        float scale = getScale();
        float scaleFactor = scaleGestureDetector.getScaleFactor();

        //判斷drawable是否為空
        if (getDrawable() == null)
            return true;
        //判斷範圍
        if ((scale < maxScale && scale >= 1.0f) || (scale > minScale && scale <= 1.0f)){
            //Log.i("==onScale",String.valueOf(scale) + ":::" + String.valueOf(scaleFactor) + ":::" + String.valueOf(maxScale));
            if (scale * scaleFactor > maxScale){
                //Log.i("==scaleFactor",String.valueOf(scale * scaleFactor));
                    scaleFactor = maxScale/scale;
                }
            if (scale * scaleFactor < minScale){
                    scaleFactor = minScale/scale;
                }
        }
        /**
         * 限定圖片放縮的最大值和最小值
         * */
        else if (scale >= maxScale && scaleFactor > 1.0f){
            scaleFactor = maxScale/scale;
        }else if (scale <= minScale/2 && scaleFactor < 1.0f){
            //Log.i("==scale",String.valueOf(scaleFactor));
            scaleFactor = minScale/(2*scale);
        }

        //Log.i("==scaleFactor 333",String.valueOf(scale * scaleFactor));

        //注意這裡要以手勢中心為縮放中心
        mMatrix.postScale(scaleFactor,scaleFactor,
                scaleGestureDetector.getFocusX(),scaleGestureDetector.getFocusY());

        transBoderAndCenter();

        setImageMatrix(mMatrix);

        return true;
    }


    //在縮放時候進行邊界控制和中心點的控制
    private void transBoderAndCenter() {
        //設定x和y的邊界值
        float Dx = 0;
        float Dy = 0;
        RectF rectF = getRectF();
        int width = getWidth();
        int height = getHeight();

        float l = rectF.left;
        float r = rectF.right;
        float t = rectF.top;
        float b = rectF.bottom;


        float w = rectF.width();
        float h = rectF.height();

        if (w >= width){
            if (l > 0){
                Dx = -l;
            }
            if (r < width){
                Dx = width - r;
            }
        }

        if (h >= height){
            if (t > 0){
                Dy = -t;
            }
            if (b < height){
                Dy = height - b;
            }
        }

        if (w < width){
            Dx = width/2 - r + w/2;
        }
        if (h < height){
            Dy = height/2 - b + h/2;
        }

        mMatrix.postTranslate(Dx,Dy);


    }

    private float getScale() {
        float[] values = new float[9];
        mMatrix.getValues(values);
        float value = values[Matrix.MSCALE_X];
        return value;
    }

    //放縮開始時候
    @Override
    public boolean