9

How to set Max and Min zoom levels for Pinch-Zoom?


Here is my code: //

public class TouchImageView extends ImageView {

     private static final String TAG = "Touch";

        // These matrices will be used to move and zoom image
        Matrix matrix = new Matrix();
        Matrix savedMatrix = new Matrix();
        static PinchZoomExample sPinchZoomExample = null;
        // 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;
        static Bitmap sCurrentImage;

        // Remember some things for zooming
        PointF start = new PointF();
        PointF mid = new PointF();
        float oldDist = 1f;

        Context context;


        public TouchImageView(Context context) {
            super(context);
            super.setClickable(true);
            this.context = context;

            matrix.setTranslate(1f, 1f);
            setImageMatrix(matrix);
            setScaleType(ScaleType.MATRIX);

            setOnTouchListener(new OnTouchListener() {

                @Override
                public boolean onTouch(View v, MotionEvent rawEvent) {
                    WrapMotionEvent event = WrapMotionEvent.wrap(rawEvent);

                    // Dump touch event to log
                   /* if (Viewer.isDebug == true){
                        dumpEvent(event);
                    }*/

                    // Handle touch events here...
                    switch (event.getAction() & MotionEvent.ACTION_MASK) {
                    case MotionEvent.ACTION_DOWN:
                        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);
                        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:
                        int xDiff = (int) Math.abs(event.getX() - start.x);
                        int yDiff = (int) Math.abs(event.getY() - start.y);
                        if (xDiff < 8 && yDiff < 8){
                            performClick();
                            sPinchZoomExample.displayGallery();
                        }
                    case MotionEvent.ACTION_POINTER_UP:
                        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) {
                            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);

                                //Canvas canvas = new Canvas();

//                              Bitmap bm = Bitmap.createBitmap(sCurrentImage,0, 0, sCurrentImage.getWidth()
//                                      , sCurrentImage.getHeight(), matrix, true);
                                Log.d("SCALE", "scale=" + scale + "  " + getWidth() + "  " + getHeight());
                                //bm.recycle();
                            }
                        }
                        break;
                    }

                    setImageMatrix(matrix);
                    return true; // indicate event was handled
                }

            });
        }


        public void setImage(Bitmap bm, int displayWidth, int displayHeight , PinchZoomExample pze) { 
            super.setImageBitmap(bm);
            sCurrentImage = bm;
            sPinchZoomExample = pze;
            //Fit to screen.
            float scale;
            if ((displayHeight / bm.getHeight()) >= (displayWidth / bm.getWidth())){
                scale =  (float)displayWidth / (float)bm.getWidth();
            } else {
                scale = (float)displayHeight / (float)bm.getHeight();
            }

            savedMatrix.set(matrix);
            matrix.set(savedMatrix);
            matrix.postScale(scale, scale, mid.x, mid.y);
            setImageMatrix(matrix);


            // Center the image
            float redundantYSpace = (float)displayHeight - (scale * (float)bm.getHeight()) ;
            float redundantXSpace = (float)displayWidth - (scale * (float)bm.getWidth());

            redundantYSpace /= (float)2;
            redundantXSpace /= (float)2;


            savedMatrix.set(matrix);
            matrix.set(savedMatrix);
            matrix.postTranslate(redundantXSpace, redundantYSpace);   //matrix.postTranslate(50, 50);
            setImageMatrix(matrix);


        }




        /** Determine the space between the first two fingers */
        private float spacing(WrapMotionEvent event) {
            // ...
            float x = event.getX(0) - event.getX(1);
            float y = event.getY(0) - event.getY(1);
            return FloatMath.sqrt(x * x + y * y);
        }

        /** Calculate the mid point of the first two fingers */
        private void midPoint(PointF point, WrapMotionEvent event) {
            // ...
            float x = event.getX(0) + event.getX(1);
            float y = event.getY(0) + event.getY(1);
            point.set(x / 2, y / 2);
        }

}
Kirk Woll
  • 76,112
  • 22
  • 180
  • 195
Audum
  • 219
  • 2
  • 3
  • 5

4 Answers4

7
private static final float MIN_ZOOM = 1.0f;
private static final float MAX_ZOOM = 5.0f;

scale = Math.max(MIN_ZOOM, Math.min(scale, MAX_ZOOM));
sth
  • 222,467
  • 53
  • 283
  • 367
Akos Cz
  • 12,711
  • 1
  • 37
  • 32
  • 2
    Downgraded. This will limit the scale for one action (zoom gesture). With multiple actions user could scale beyond max or min zoom. – ALiGOTec Oct 10 '12 at 14:56
  • Sorry, I don't follow. Could you elaborate on your comment about multiple actions and how they could scale beyond max or min zoom. – Akos Cz Oct 10 '12 at 18:31
  • On every `onTouch` event a new `scale` is computed (as `newDist / oldDist`) and this scale is applied to `matrix`, giving a total_scale as matrix_current_scale multiplied with current_scale. On next touch event this process will repeat (possibly giving a total_scale grater than the MAX_ZOOM). – ALiGOTec Oct 11 '12 at 09:24
  • Ok that's fine, BUT ... my example above simply demonstrates how to ensure that the value of "scale" is strictly bound by MIN_ZOOM and MAX_ZOOM. – Akos Cz Oct 11 '12 at 17:14
3

Check my answer here. It worked with very little extra coding effort.

https://stackoverflow.com/a/18395969/2709830

Community
  • 1
  • 1
Arjun
  • 361
  • 2
  • 4
0
if(mapZoom > MAX_ZOOM && (newDist > oldDist) ) {
    break;
} else if(mapZoom < MIN_Zoom && (newDist < oldDist) ){
    break;
}

matrix.postScale(zoomScale, zoomScale, mid.x, mid.y);  
savedMatrixZoom.set(matrix);  

It works fine but still I loose that smoothness and is too sensitive.

Stephan
  • 41,764
  • 65
  • 238
  • 329
nagaraj
  • 89
  • 1
  • 5
0

Create a temporary matrix (temp), save the current matrix in it and scal the temp matrix. Then check the MSCALE_X value of temp matrix.

If zoom of your temp matrix is within your limit, postscale your matrix and save it in another matrix (savedMatrixZoom). If it is over your limit just load your current matrix from SavedMatrixZoom.

    else if (mode == ZOOM) {
        float newDist = spacing(event);
        Log.d(TAG, "newDist=" + newDist);
        if (newDist > 10f) {
            matrix.set(savedMatrix);
            zoomScale = newDist / oldDist;

            Matrix temp = new Matrix();
            temp.set(matrix);
            temp.postScale(zoomScale, zoomScale, mid.x, mid.y);
            mapZoom = getValue(temp, Matrix.MSCALE_X);
            if (mapZoom < MAX_ZOOM && mapZoom > MIN_ZOOM) {
                matrix.postScale(zoomScale, zoomScale, mid.x, mid.y);
                savedMatrixZoom.set(matrix);
            } else {
                matrix.set(savedMatrixZoom);
            }
        }
    }

Hope it helps

GuilhE
  • 11,591
  • 16
  • 75
  • 116