通过手势实现Android ImageView 缩放

jopen 10年前


方法一:

将以下代码写到MulitPointTouchListener.java中,然后对你相应的图片进行OnTouchListener。
例如:imageView.setOnTouchListener(new MulitPointTouchListener ());

在xml中要将ImageView的缩放格式改成Matrix

例如:android:scaleType="matrix"

这样就可以实现图片的缩放了

 

下面是MulitPointTouchListener.java代码:

public class MulitPointTouchListener implements OnTouchListener {             private static final String TAG = "Touch";             // These matrices will be used to move and zoom image             Matrix matrix = new Matrix();             Matrix savedMatrix = new Matrix();                 // We can be in one of these 3 states             static final int NONE = 0;             static final int DRAG = 1;             static final int ZOOM = 2;             int mode = NONE;                 // Remember some things for zooming             PointF start = new PointF();             PointF mid = new PointF();             float oldDist = 1f;                 @Override            public boolean onTouch(View v, MotionEvent event) {                         ImageView view = (ImageView) v;                     // Log.e("view_width",                     // view.getImageMatrix()..toString()+"*"+v.getWidth());                     // Dump touch event to log                     dumpEvent(event);                         // Handle touch events here...                     switch (event.getAction() & MotionEvent.ACTION_MASK) {                     case MotionEvent.ACTION_DOWN:                                 matrix.set(view.getImageMatrix());                             savedMatrix.set(matrix);                             start.set(event.getX(), event.getY());                             //Log.d(TAG, "mode=DRAG");                             mode = DRAG;                                                             //Log.d(TAG, "mode=NONE");                             break;                     case MotionEvent.ACTION_POINTER_DOWN:                             oldDist = spacing(event);                             //Log.d(TAG, "oldDist=" + oldDist);                             if (oldDist > 10f) {                                     savedMatrix.set(matrix);                                     midPoint(mid, event);                                     mode = ZOOM;                                     //Log.d(TAG, "mode=ZOOM");                             }                             break;                     case MotionEvent.ACTION_UP:                     case MotionEvent.ACTION_POINTER_UP:                             mode = NONE;                             //Log.e("view.getWidth", view.getWidth() + "");                             //Log.e("view.getHeight", view.getHeight() + "");                                 break;                     case MotionEvent.ACTION_MOVE:                             if (mode == DRAG) {                                     // ...                                     matrix.set(savedMatrix);                                     matrix.postTranslate(event.getX() - start.x, event.getY()                                                     - start.y);                             } else if (mode == ZOOM) {                                     float newDist = spacing(event);                                     //Log.d(TAG, "newDist=" + newDist);                                     if (newDist > 10f) {                                             matrix.set(savedMatrix);                                             float scale = newDist / oldDist;                                             matrix.postScale(scale, scale, mid.x, mid.y);                                     }                             }                             break;                     }                         view.setImageMatrix(matrix);                     return true; // indicate event was handled             }                 private void dumpEvent(MotionEvent event) {                     String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE",                                     "POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" };                     StringBuilder sb = new StringBuilder();                     int action = event.getAction();                     int actionCode = action & MotionEvent.ACTION_MASK;                     sb.append("event ACTION_").append(names[actionCode]);                     if (actionCode == MotionEvent.ACTION_POINTER_DOWN                                     || actionCode == MotionEvent.ACTION_POINTER_UP) {                             sb.append("(pid ").append(                                             action >> MotionEvent.ACTION_POINTER_ID_SHIFT);                             sb.append(")");                     }                     sb.append("[");                     for (int i = 0; i < event.getPointerCount(); i++) {                             sb.append("#").append(i);                             sb.append("(pid ").append(event.getPointerId(i));                             sb.append(")=").append((int) event.getX(i));                             sb.append(",").append((int) event.getY(i));                             if (i + 1 < event.getPointerCount())                                     sb.append(";");                     }                     sb.append("]");                     //Log.d(TAG, sb.toString());             }                             private float spacing(MotionEvent event) {                     float x = event.getX(0) - event.getX(1);                     float y = event.getY(0) - event.getY(1);                     return FloatMath.sqrt(x * x + y * y);             }                             private void midPoint(PointF point, MotionEvent event) {                     float x = event.getX(0) + event.getX(1);                     float y = event.getY(0) + event.getY(1);                     point.set(x / 2, y / 2);             }     }  

 

方法二:自定义一个ImageView,例如TouchImageView:

import android.content.Context;  import android.graphics.Matrix;  import android.graphics.PointF;  import android.graphics.drawable.Drawable;  import android.util.AttributeSet;  import android.util.Log;  import android.view.MotionEvent;  import android.view.ScaleGestureDetector;  import android.view.View;  import android.widget.ImageView;    public class TouchImageView extends ImageView {        Matrix matrix;        // We can be in one of these 3 states      static final int NONE = 0;      static final int DRAG = 1;      static final int ZOOM = 2;      int mode = NONE;        // Remember some things for zooming      PointF last = new PointF();      PointF start = new PointF();      float minScale = 1f;      float maxScale = 3f;      float[] m;          int viewWidth, viewHeight;      static final int CLICK = 3;      float saveScale = 1f;      protected float origWidth, origHeight;      int oldMeasuredWidth, oldMeasuredHeight;          ScaleGestureDetector mScaleDetector;        Context context;        public TouchImageView(Context context) {          super(context);          sharedConstructing(context);      }        public TouchImageView(Context context, AttributeSet attrs) {          super(context, attrs);          sharedConstructing(context);      }            private void sharedConstructing(Context context) {          super.setClickable(true);          this.context = context;          mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());          matrix = new Matrix();          m = new float[9];          setImageMatrix(matrix);          setScaleType(ScaleType.MATRIX);            setOnTouchListener(new OnTouchListener() {                @Override              public boolean onTouch(View v, MotionEvent event) {                  mScaleDetector.onTouchEvent(event);                  PointF curr = new PointF(event.getX(), event.getY());                    switch (event.getAction()) {                      case MotionEvent.ACTION_DOWN:                       last.set(curr);                          start.set(last);                          mode = DRAG;                          break;                                                case MotionEvent.ACTION_MOVE:                          if (mode == DRAG) {                              float deltaX = curr.x - last.x;                              float deltaY = curr.y - last.y;                              float fixTransX = getFixDragTrans(deltaX, viewWidth, origWidth * saveScale);                              float fixTransY = getFixDragTrans(deltaY, viewHeight, origHeight * saveScale);                              matrix.postTranslate(fixTransX, fixTransY);                              fixTrans();                              last.set(curr.x, curr.y);                          }                          break;                        case MotionEvent.ACTION_UP:                          mode = NONE;                          int xDiff = (int) Math.abs(curr.x - start.x);                          int yDiff = (int) Math.abs(curr.y - start.y);                          if (xDiff < CLICK && yDiff < CLICK)                              performClick();                          break;                        case MotionEvent.ACTION_POINTER_UP:                          mode = NONE;                          break;                  }                                    setImageMatrix(matrix);                  invalidate();                  return true; // indicate event was handled              }            });      }        public void setMaxZoom(float x) {          maxScale = x;      }        private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {          @Override          public boolean onScaleBegin(ScaleGestureDetector detector) {              mode = ZOOM;              return true;          }            @Override          public boolean onScale(ScaleGestureDetector detector) {              float mScaleFactor = detector.getScaleFactor();              float origScale = saveScale;              saveScale *= mScaleFactor;              if (saveScale > maxScale) {                  saveScale = maxScale;                  mScaleFactor = maxScale / origScale;              } else if (saveScale < minScale) {                  saveScale = minScale;                  mScaleFactor = minScale / origScale;              }                if (origWidth * saveScale <= viewWidth || origHeight * saveScale <= viewHeight)                  matrix.postScale(mScaleFactor, mScaleFactor, viewWidth / 2, viewHeight / 2);              else                  matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY());                fixTrans();              return true;          }      }        void fixTrans() {          matrix.getValues(m);          float transX = m[Matrix.MTRANS_X];          float transY = m[Matrix.MTRANS_Y];                    float fixTransX = getFixTrans(transX, viewWidth, origWidth * saveScale);          float fixTransY = getFixTrans(transY, viewHeight, origHeight * saveScale);            if (fixTransX != 0 || fixTransY != 0)              matrix.postTranslate(fixTransX, fixTransY);      }        float getFixTrans(float trans, float viewSize, float contentSize) {          float minTrans, maxTrans;            if (contentSize <= viewSize) {              minTrans = 0;              maxTrans = viewSize - contentSize;          } else {              minTrans = viewSize - contentSize;              maxTrans = 0;          }            if (trans < minTrans)              return -trans + minTrans;          if (trans > maxTrans)              return -trans + maxTrans;          return 0;      }            float getFixDragTrans(float delta, float viewSize, float contentSize) {          if (contentSize <= viewSize) {              return 0;          }          return delta;      }        @Override      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {          super.onMeasure(widthMeasureSpec, heightMeasureSpec);          viewWidth = MeasureSpec.getSize(widthMeasureSpec);          viewHeight = MeasureSpec.getSize(heightMeasureSpec);                    //          // Rescales image on rotation          //          if (oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight                  || viewWidth == 0 || viewHeight == 0)              return;          oldMeasuredHeight = viewHeight;          oldMeasuredWidth = viewWidth;            if (saveScale == 1) {              //Fit to screen.              float scale;                Drawable drawable = getDrawable();              if (drawable == null || drawable.getIntrinsicWidth() == 0 || drawable.getIntrinsicHeight() == 0)                  return;              int bmWidth = drawable.getIntrinsicWidth();              int bmHeight = drawable.getIntrinsicHeight();                            Log.d("bmSize", "bmWidth: " + bmWidth + " bmHeight : " + bmHeight);                float scaleX = (float) viewWidth / (float) bmWidth;              float scaleY = (float) viewHeight / (float) bmHeight;              scale = Math.min(scaleX, scaleY);              matrix.setScale(scale, scale);                // Center the image              float redundantYSpace = (float) viewHeight - (scale * (float) bmHeight);              float redundantXSpace = (float) viewWidth - (scale * (float) bmWidth);              redundantYSpace /= (float) 2;              redundantXSpace /= (float) 2;                matrix.postTranslate(redundantXSpace, redundantYSpace);                origWidth = viewWidth - 2 * redundantXSpace;              origHeight = viewHeight - 2 * redundantYSpace;              setImageMatrix(matrix);          }          fixTrans();      }  }

然后在我们的Activity中就可以直接使用了:

public class TouchImageViewActivity extends Activity {      /** Called when the activity is first created. */      @Override      public void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.main);          TouchImageView img = (TouchImageView) findViewById(R.id.snoop);          img.setImageResource(R.drawable.snoopy);          img.setMaxZoom(4f);      }  }