ImageView Drag Limitation In Android

android, java, ontouchlistener, touch-event

Solution

Add the following parameters to the `Touch` class:

private float dx; // postTranslate X distance
private float dy; // postTranslate Y distance
private float[] matrixValues = new float[9];
float matrixX = 0; // X coordinate of matrix inside the ImageView
float matrixY = 0; // Y coordinate of matrix inside the ImageView
float width = 0; // width of drawable
float height = 0; // height of drawable

Modify your code after `case MotionEvent.ACTION_MOVE:`

if (mode == DRAG) {
        matrix.set(savedMatrix);

        matrix.getValues(matrixValues);
        matrixX = matrixValues[2];
        matrixY = matrixValues[5];
        width = matrixValues[0] * (((ImageView) view).getDrawable()
                                .getIntrinsicWidth());
        height = matrixValues[4] * (((ImageView) view).getDrawable()
                                .getIntrinsicHeight());

        dx = event.getX() - start.x;
        dy = event.getY() - start.y;

        //if image will go outside left bound
        if (matrixX + dx < 0){
            dx = -matrixX;
        }
        //if image will go outside right bound
        if(matrixX + dx + width > view.getWidth()){
            dx = view.getWidth() - matrixX - width;
        }
        //if image will go oustside top bound
        if (matrixY + dy < 0){
            dy = -matrixY;
        }
        //if image will go outside bottom bound
        if(matrixY + dy + height > view.getHeight()){
            dy = view.getHeight() - matrixY - height;
        }
        matrix.postTranslate(dx, dy);   
    }

Problem

I have an ImageView in a layout and set OnTouchListener on ImageView to drag the ImageView. It's working perfectly. My problem is how can I prevent from move ImageView to out of layout range? This is my code: Activity class: ``` public class RepositionTestActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.reposition_test_layout); ImageView imageView = (ImageView)findViewById(R.id.android); imageView.setOnTouchListener(new Touch()); } } ``` Touch class: ``` public class Touch implements OnTouchListener { private static final int NONE = 0; private static final int DRAG = 1; private static final int ZOOM = 2; private static final float MIN_ZOOM = 1f; private static final float MAX_ZOOM = 5f; private Matrix matrix = new Matrix(); private Matrix savedMatrix = new Matrix(); private PointF start = new PointF(); private PointF mid = new PointF(); private int mode = NONE; private float oldDistance = 1f; public boolean onTouch(View view, MotionEvent event) { ImageView imageView = (ImageView)view; switch(event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: savedMatrix.set(matrix); start.set(event.getX(), event.getY()); mode = DRAG; break; case MotionEvent.ACTION_POINTER_DOWN: oldDistance = spacing(event); if(oldDistance > 10f) { savedMatrix.set(matrix); midPoint(mid, event); mode = ZOOM; } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: mode = NONE; 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 newDistance = spacing(event); if(newDistance > 10f) { matrix.set(savedMatrix); float scale = newDistance / oldDistance; float[] values = new float[9]; matrix.getValues(values); float currentScale = values[Matrix.MSCALE_X]; if(scale * currentScale > MAX_ZOOM) scale = MAX_ZOOM / currentScale; else if (scale * currentScale < MIN_ZOOM) scale = MIN_ZOOM / currentScale; matrix.postScale(scale, scale, mid.x, mid.y); } } break; } imageView.setImageMatrix(matrix); return true; } 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) { point.set((event.getX(0) + event.getX(1)) / 2, (event.getY(0) + event.getY(1)) / 2); } } ``` Layout xml: ``` <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/reposition_test_layout" android:layout_width="fill_parent" android:layout_height="fill_parent" > <ImageView android:id="@+id/android" android:src="@drawable/android" android:layout_width="300dp" android:layout_height="300dp" android:scaleType="matrix" android:contentDescription="@string/android_description" > </ImageView> </LinearLayout> ```

Original source