title: Decide between Fling and Drag gesture in ImageView
body: <p>I use code from <a href="https://stackoverflow.com/a/7458910/581567">Mike Ortiz</a> to zoom in ImageView and would like to add fling gestures, but drag gesture is sometimes caught as fling gesture, is there any way to filter right gesture? In some galleries both zoom and fling to get next image works fine.  Thanks for any hint.
  Code:</p>
  
  <pre><code>    public class TouchImageView extends ImageView {
  
      Matrix matrix = new Matrix();
      private static final String TAG = "Touch";
  
      // 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;
  
      float redundantXSpace, redundantYSpace;
  
      float width, height;
      static final int CLICK = 3;
      float saveScale = 1f;
      float right, bottom, origWidth, origHeight, bmWidth, bmHeight;
  
      ScaleGestureDetector mScaleDetector;
      GestureDetector gdt;
  
      Context context;
  
  
      public TouchImageView(Context context) {
          super(context);
          super.setClickable(true);
          this.context = context;
          mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
          gdt = new GestureDetector(new GestureListener());
          matrix.setTranslate(1f, 1f);
          m = new float[9];
          setImageMatrix(matrix);
          setScaleType(ScaleType.MATRIX);
  
          setOnTouchListener(new OnTouchListener() {
  
              @Override
              public boolean onTouch(View v, MotionEvent event) {
                  mScaleDetector.onTouchEvent(event);
                  gdt.onTouchEvent(event);
                  matrix.getValues(m);
                  float x = m[Matrix.MTRANS_X];
                  float y = m[Matrix.MTRANS_Y];
                  PointF curr = new PointF(event.getX(), event.getY());
  
                  switch (event.getAction()) {
                      case MotionEvent.ACTION_DOWN:
                          last.set(event.getX(), event.getY());
                          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 scaleWidth = Math.round(origWidth * saveScale);
                              float scaleHeight = Math.round(origHeight * saveScale);
                              if (scaleWidth &lt; width) {
                                  deltaX = 0;
                                  if (y + deltaY &gt; 0)
                                      deltaY = -y;
                                  else if (y + deltaY &lt; -bottom)
                                      deltaY = -(y + bottom); 
                              } else if (scaleHeight &lt; height) {
                                  deltaY = 0;
                                  if (x + deltaX &gt; 0)
                                      deltaX = -x;
                                  else if (x + deltaX &lt; -right)
                                      deltaX = -(x + right);
                              } else {
                                  if (x + deltaX &gt; 0)
                                      deltaX = -x;
                                  else if (x + deltaX &lt; -right)
                                      deltaX = -(x + right);
  
                                  if (y + deltaY &gt; 0)
                                      deltaY = -y;
                                  else if (y + deltaY &lt; -bottom)
                                      deltaY = -(y + bottom);
                              }
                              matrix.postTranslate(deltaX, deltaY);
                              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 &lt; CLICK &amp;&amp; yDiff &lt; CLICK)
                              performClick();
                          break;
  
                      case MotionEvent.ACTION_POINTER_UP:
                          mode = NONE;
                          break;
                  }
                  setImageMatrix(matrix);
                  invalidate();
                  return true; // indicate event was handled
              }
  
          });
      }
  
      @Override
      public void setImageBitmap(Bitmap bm) { 
          super.setImageBitmap(bm);
          bmWidth = bm.getWidth();
          bmHeight = bm.getHeight();
      }
  
      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 = (float)Math.min(Math.max(.95f, detector.getScaleFactor()), 1.05);
              float mScaleFactor = detector.getScaleFactor();
              float origScale = saveScale;
              saveScale *= mScaleFactor;
              if (saveScale &gt; maxScale) {
                  saveScale = maxScale;
                  mScaleFactor = maxScale / origScale;
              } else if (saveScale &lt; minScale) {
                  saveScale = minScale;
                  mScaleFactor = minScale / origScale;
              }
              right = width * saveScale - width - (2 * redundantXSpace * saveScale);
              bottom = height * saveScale - height - (2 * redundantYSpace * saveScale);
              if (origWidth * saveScale &lt;= width || origHeight * saveScale &lt;= height) {
                  matrix.postScale(mScaleFactor, mScaleFactor, width / 2, height / 2);
                  if (mScaleFactor &lt; 1) {
                      matrix.getValues(m);
                      float x = m[Matrix.MTRANS_X];
                      float y = m[Matrix.MTRANS_Y];
                      if (mScaleFactor &lt; 1) {
                          if (Math.round(origWidth * saveScale) &lt; width) {
                              if (y &lt; -bottom)
                                  matrix.postTranslate(0, -(y + bottom));
                              else if (y &gt; 0)
                                  matrix.postTranslate(0, -y);
                          } else {
                              if (x &lt; -right) 
                                  matrix.postTranslate(-(x + right), 0);
                              else if (x &gt; 0) 
                                  matrix.postTranslate(-x, 0);
                          }
                      }
                  }
              } else {
                  matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY());
                  matrix.getValues(m);
                  float x = m[Matrix.MTRANS_X];
                  float y = m[Matrix.MTRANS_Y];
                  if (mScaleFactor &lt; 1) {
                      if (x &lt; -right) 
                          matrix.postTranslate(-(x + right), 0);
                      else if (x &gt; 0) 
                          matrix.postTranslate(-x, 0);
                      if (y &lt; -bottom)
                          matrix.postTranslate(0, -(y + bottom));
                      else if (y &gt; 0)
                          matrix.postTranslate(0, -y);
                  }
              }
              return true;
  
          }
      }
  
      @Override
      protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
      {
          super.onMeasure(widthMeasureSpec, heightMeasureSpec);
          width = MeasureSpec.getSize(widthMeasureSpec);
          height = MeasureSpec.getSize(heightMeasureSpec);
          //Fit to screen.
          float scale;
          float scaleX =  (float)width / (float)bmWidth;
          float scaleY = (float)height / (float)bmHeight;
          scale = Math.min(scaleX, scaleY);
          matrix.setScale(scale, scale);
          setImageMatrix(matrix);
          saveScale = 1f;
  
          // Center the image
          redundantYSpace = (float)height - (scale * (float)bmHeight) ;
          redundantXSpace = (float)width - (scale * (float)bmWidth);
          redundantYSpace /= (float)2;
          redundantXSpace /= (float)2;
  
          matrix.postTranslate(redundantXSpace, redundantYSpace);
  
          origWidth = width - 2 * redundantXSpace;
          origHeight = height - 2 * redundantYSpace;
          right = width * saveScale - width - (2 * redundantXSpace * saveScale);
          bottom = height * saveScale - height - (2 * redundantYSpace * saveScale);
          setImageMatrix(matrix);
      }
  
      class GestureListener extends SimpleOnGestureListener {
          private   int SWIPE_MIN_DISTANCE = 120;
          private   int SWIPE_THRESHOLD_VELOCITY = 200;
  
          @Override
          public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
              if(e1.getX() - e2.getX() &gt; SWIPE_MIN_DISTANCE &amp;&amp; Math.abs(velocityX) &gt; SWIPE_THRESHOLD_VELOCITY) {
  
                  Toast.makeText(context, "Right to left "+Math.abs(velocityX), Toast.LENGTH_SHORT).show();
                  Log.d(TAG, "Velocity "+Math.abs(velocityX));
                  Log.d(TAG, "Distance "+(e1.getX() - e2.getX()));
  
                  return false; // Right to left
              }  else if (e2.getX() - e1.getX() &gt; SWIPE_MIN_DISTANCE &amp;&amp; Math.abs(velocityX) &gt; SWIPE_THRESHOLD_VELOCITY) {
  
                  Toast.makeText(context, "Left to right "+Math.abs(velocityX), Toast.LENGTH_SHORT).show();
                  Log.d(TAG, "Velocity "+Math.abs(velocityX));
                  Log.d(TAG, "Distance "+(e2.getX() - e1.getX()));
  
                  return false; // Left to right
              }
              if(e1.getY() - e2.getY() &gt; SWIPE_MIN_DISTANCE &amp;&amp; Math.abs(velocityY) &gt; SWIPE_THRESHOLD_VELOCITY) {
                  return false; // Bottom to top
              }  else if (e2.getY() - e1.getY() &gt; SWIPE_MIN_DISTANCE &amp;&amp; Math.abs(velocityY) &gt; SWIPE_THRESHOLD_VELOCITY) {
                  return false; // Top to bottom
              }
              return false;
          }
      }
  }
  </code></pre>