Reputation: 219
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);
}
}
Upvotes: 9
Views: 13338
Reputation: 9
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
Upvotes: 0
Reputation: 371
Check my answer here. It worked with very little extra coding effort.
https://stackoverflow.com/a/18395969/2709830
Upvotes: 3
Reputation: 159
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.
Upvotes: 0
Reputation: 12790
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));
Upvotes: 7