Note that there are some explanatory texts on larger screens.

plurals
  1. PODecide between Fling and Drag gesture in ImageView
    text
    copied!<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>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload