Restrict ImageView movement

107 Views Asked by At

I have to an ImageView named imgForeground which can be rotated, zoomed and moved but it can move to outside the screen. how can I restrict its movement not to go outside of screen? Is there any library for this? it is something like the apps that you can select a label, move and resize it and place it everywhere you want.

<ImageView
    android:id="@+id/imgForground"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_centerInParent="true"
    android:src="@drawable/icon" />

This code for zoom, move and rotate:

@Override
public boolean onTouch(View v, MotionEvent event) {
    ImageView view = (ImageView) v;
    view.setScaleType(ImageView.ScaleType.MATRIX);
    float scale;

    // Dump touch event to log
    dumpEvent(event);

    // Handle touch events here...
    switch (event.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN: //first finger down only
            savedMatrix.set(matrix);
            start.set(event.getX(), event.getY());
            Log.d(TAG, "mode=DRAG");
            mode = DRAG;
            break;

        case MotionEvent.ACTION_POINTER_DOWN:
            oldDist = spacing(event);
            if (oldDist > 10f) {
                savedMatrix.set(matrix);
                midPoint(mid, event);
                mode = ZOOM;
            }
            lastEvent = new float[4];
            lastEvent[0] = event.getX(0);
            lastEvent[1] = event.getX(1);
            lastEvent[2] = event.getY(0);
            lastEvent[3] = event.getY(1);
            d = rotation(event);
            break;

        case MotionEvent.ACTION_UP: //first finger lifted
        case MotionEvent.ACTION_POINTER_UP: //second finger lifted
            mode = NONE;
            Log.d(TAG, "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 && event.getPointerCount() == 2) {
                float newDist = spacing(event);
                matrix.set(savedMatrix);
                if (newDist > 10f) {
                    scale = newDist / oldDist;
                    matrix.postScale(scale, scale, mid.x, mid.y);
                }
                if (lastEvent != null) {
                    newRot = rotation(event);
                    float r = newRot - d;
                    matrix.postRotate(r, view.getMeasuredWidth() / 2,
                            view.getMeasuredHeight() / 2);
                }
            }
            break;

    }
    // Perform the transformation
    view.setImageMatrix(matrix);

    return true; // indicate event was handled
}

private float rotation(MotionEvent event) {
    double delta_x = (event.getX(0) - event.getX(1));
    double delta_y = (event.getY(0) - event.getY(1));
    double radians = Math.atan2(delta_y, delta_x);

    return (float) Math.toDegrees(radians);
}

private float spacing(MotionEvent event) {
    float x = event.getX(0) - event.getX(1);
    float y = event.getY(0) - event.getY(1);
    return (float) Math.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);

}

/**
 * Show an event in the LogCat view, for debugging
 */
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());

}
1

There are 1 best solutions below

0
On

Mobile device screen is a region of plane(x,y) where (0,0) coordinate is top-left corner. You need to calculate the imageView position w.r.t screen region. In your event handler, get the position of your imageView.

int[] location = new int[2];
view.getLocationOnScreen(location);
int x = location[0];
int y = location[1];

Now get the displayed size of an image inside the image view.

int ih=view.getMeasuredHeight();//height of imageView
int iw=view.getMeasuredWidth();//width of imageView
int iH=view.getDrawable().getIntrinsicHeight();//original height of underlying image
int iW=view.getDrawable().getIntrinsicWidth();//original width of underlying image

if (ih/iH<=iw/iW)
    iw=iW*ih/iH;    //rescaled width of image within ImageView
else 
    ih= iH*iw/iW;   //rescaled height of image within ImageView

Now get the width and height of screen

DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int deviceHeight = displayMetrics.heightPixels;
int deviceWidth = displayMetrics.widthPixels;

If imageView moves towards left

if(x>0)
    //Move towards left functionality

If imageView moves towards top

if(y>0)
    //Move towards top functionality

If imageView moves towards right

if(x+iw < deviceWidth)
    //Move towards right functionality

If imageView moves towards bottom

if(y+ih < deviceHeight)
    //Move towards right functionality