I'm trying to implement the double tap and the pinch to zoom activity. I wrote some code for the first one but it seem not to work (i can use only the android emulator for eclipse for now. So I'm not sure if my result is the right one)
Anyway I'm not able to understand what am I doing wrong. I'm surely forgetting something.
This is my code:
public class ImageZoomView extends View implements OnGestureListener {
private static final int SCALING_FACTOR = 50;
private final int LANDSCAPE = 1;
private GestureDetector gestureDetector;
private Drawable image = null;
private int scalefactor = 0;
private int orientation;
private int zoomCtr = 0;
private long lastTouchTime = 0;
private int winX, winY, imageX, imageY, scrollX = 0, scrollY = 0, left,
top, bottom, right;
public ImageZoomView(Context context, int orientation) {
super(context);
setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT));
this.orientation = orientation;
gestureDetector = new GestureDetector(this);
}
public void setImage(Drawable bitmap, Activity activity) {
image = bitmap;
imageSetting(activity);
}
public void setImage(Bitmap bitmap, Activity activity) {
image = new BitmapDrawable(bitmap).getCurrent();
imageSetting(activity);
}
/**
* Works in both landscape and portrait mode.
*/
private void imageSetting(Activity activity) {
scrollX = scrollY = 0;
scalefactor = 0;
imageX = winX = activity.getWindow().getWindowManager()
.getDefaultDisplay().getWidth();
imageY = winY = activity.getWindow().getWindowManager()
.getDefaultDisplay().getHeight();
if (orientation == LANDSCAPE) {
imageX = 3 * imageY / 4;
}
calculatePos();
}
public void calculatePos() {
int tempx, tempy;
tempx = imageX + imageX * scalefactor / 100;
tempy = imageY + imageY * scalefactor / 100;
left = (winX - tempx) / 2;
top = (winY - tempy) / 2;
right = (winX + tempx) / 2;
bottom = (winY + tempy) / 2;
invalidate();
}
/**
* Redraws the bitmap when zoomed or scrolled.
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (image == null)
return;
image.setBounds(left + scrollX, top + scrollY, right + scrollX, bottom
+ scrollY);
image.draw(canvas);
}
public void zoomIn() {
scalefactor += SCALING_FACTOR;
calculatePos();
}
public void zoomOut() {
if (scalefactor == 0)
return;
scrollX = scrollY = 0;
scalefactor -= SCALING_FACTOR;
calculatePos();
}
public void scroll(int x, int y) {
scrollX += x / 5;
scrollY += y / 5;
if (scrollX + left > 0) {
scrollX = 0 - left;
} else if (scrollX + right < winX) {
scrollX = winX - right;
}
if (scrollY + top > 0) {
scrollY = 0 - top;
} else if (scrollY + bottom < winY) {
scrollY = winY - bottom;
}
invalidate();
}
@Override
public boolean onTouchEvent(MotionEvent me) {
boolean onTouchEvent = gestureDetector.onTouchEvent(me);
return onTouchEvent;
}
@Override
public boolean onDown(MotionEvent arg0) {
long thisTime = arg0.getEventTime();
if (thisTime - lastTouchTime < 250) {
lastTouchTime = -1;
onDoubleTap();
return true;
}
lastTouchTime = thisTime;
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
if (zoomCtr == 0)
return false;
scroll((int) (e2.getX() - e1.getX()), (int) (e2.getY() - e1.getY()));
return true;
}
private void onDoubleTap() {
if (zoomCtr == 0) {
zoomCtr++;
zoomIn();
return;
}
zoomCtr--;
zoomOut();
}
}
And this is where I call the activity:
public class FullScreenPhoto extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_full_screen_photo);
Intent intent = getIntent();
String path = intent.getStringExtra("Path");
ImageView img = (ImageView)findViewById(R.id.photo);
img.setImageURI(Uri.parse(path));
ImageZoomView imageView = new ImageZoomView(
this,getWindow().getWindowManager().getDefaultDisplay().getOrientation());
this.setContentView(imageView);
}
}
It display the full image on the screen but when tapping on it, nothing happens.
Great create a class called ZoomFunctionality
ZoomFunctionality
package com.androidhive.work;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.ImageView;
public class ZoomFunctionality extends ImageView {
Matrix matrix = new Matrix();
// 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;
Context context;
public ZoomFunctionality(Context context) {
super(context);
sharedConstructing(context);
}
public ZoomFunctionality(Context context, AttributeSet attrs) {
super(context, attrs);
sharedConstructing(context);
}
private void sharedConstructing(Context context) {
super.setClickable(true);
this.context = context;
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
matrix.setTranslate(1f, 1f);
m = new float[9];
setImageMatrix(matrix);
setScaleType(ScaleType.MATRIX);
setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
mScaleDetector.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 < width) {
deltaX = 0;
if (y + deltaY > 0)
deltaY = -y;
else if (y + deltaY < -bottom)
deltaY = -(y + bottom);
} else if (scaleHeight < height) {
deltaY = 0;
if (x + deltaX > 0)
deltaX = -x;
else if (x + deltaX < -right)
deltaX = -(x + right);
} else {
if (x + deltaX > 0)
deltaX = -x;
else if (x + deltaX < -right)
deltaX = -(x + right);
if (y + deltaY > 0)
deltaY = -y;
else if (y + deltaY < -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 < CLICK && yDiff < 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);
if (bm != null) {
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 = detector.getScaleFactor();
float origScale = saveScale;
saveScale *= mScaleFactor;
if (saveScale > maxScale) {
saveScale = maxScale;
mScaleFactor = maxScale / origScale;
} else if (saveScale < minScale) {
saveScale = minScale;
mScaleFactor = minScale / origScale;
}
right = width * saveScale - width
- (2 * redundantXSpace * saveScale);
bottom = height * saveScale - height
- (2 * redundantYSpace * saveScale);
if (origWidth * saveScale <= width
|| origHeight * saveScale <= height) {
matrix.postScale(mScaleFactor, mScaleFactor, width / 2,
height / 2);
if (mScaleFactor < 1) {
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
if (mScaleFactor < 1) {
if (Math.round(origWidth * saveScale) < width) {
if (y < -bottom)
matrix.postTranslate(0, -(y + bottom));
else if (y > 0)
matrix.postTranslate(0, -y);
} else {
if (x < -right)
matrix.postTranslate(-(x + right), 0);
else if (x > 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 < 1) {
if (x < -right)
matrix.postTranslate(-(x + right), 0);
else if (x > 0)
matrix.postTranslate(-x, 0);
if (y < -bottom)
matrix.postTranslate(0, -(y + bottom));
else if (y > 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);
}
}
Now when ever you want to call the ZoomFunctionality
from your Activity
just write the following statement
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap bmp = BitmapFactory.decodeFile(filename, options);
ZoomFunctionality img = new ZoomFunctionality(this);
img.setImageBitmap(bmp);
img.setMaxZoom(4f);
setContentView(img);
Note
bmp: Is the bitmap image of which you want the zoom functionality
this: Its recommended that you use Activity.this
Its not necessary to use BitmapFactoryOptions but decoding from filename is required