I'm trying to implement a camera preview where user can insert images and drag/scale/rotate them as overlays. I'd also need to support zoom in/out on the camera preview which is in the background. User would be able to pinch to zoom the camera when pressing outside of the image.
The images which the user can add are ImageViews that have match_parent width and height and scale type matrix. I need to allow the touch events to pass thru to the background camera view if they're not directly touching the current image.
I found some code that allows me to perform the various image manipulations:
// ImageView drag, zoom, rotate related variable
// These matrices will be used to move and zoom image
Matrix mMatrix = new Matrix();
Matrix mSavedMatrix = new Matrix();
// We can be in one of these 3 states
public enum ImageTouchMode {
NONE,
DRAG,
ZOOM
}
ImageTouchMode mMode = ImageTouchMode.NONE;
// Remember some things for zooming
PointF mStartPoint = new PointF();
PointF mMidPoint = new PointF();
float mOldDist = 1f;
float[] mLastTouchEvent = null;
float mRotationDegrees = 0f;
float mBrightness = 0f;
public boolean onTouchEvent(MotionEvent event) {
if (!hitTestInImageMatrix(event)) {
// only handle touch events inside the transformed image matrix, not the whole image view
return false;
}
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: //first finger down only
mSavedMatrix.set(mMatrix);
mStartPoint.set(event.getX(), event.getY());
Log.d(TAG, "mode=DRAG");
mMode = ImageTouchMode.DRAG;
break;
case MotionEvent.ACTION_POINTER_DOWN:
mOldDist = spacing(event);
if (mOldDist > 10f) {
mSavedMatrix.set(mMatrix);
midPoint(mMidPoint, event);
mMode = ImageTouchMode.ZOOM;
}
mLastTouchEvent = new float[4];
mLastTouchEvent[0] = event.getX(0);
mLastTouchEvent[1] = event.getX(1);
mLastTouchEvent[2] = event.getY(0);
mLastTouchEvent[3] = event.getY(1);
mRotationDegrees = rotation(event);
break;
case MotionEvent.ACTION_UP: //first finger lifted
case MotionEvent.ACTION_POINTER_UP: //second finger lifted
mMode = ImageTouchMode.NONE;
Log.d(TAG, "mode=NONE");
break;
case MotionEvent.ACTION_MOVE:
if (mMode == ImageTouchMode.DRAG) {
float xDelta = event.getX() - mStartPoint.x;
float yDelta = event.getY() - mStartPoint.y;
mMatrix.set(mSavedMatrix);
mMatrix.postTranslate(xDelta, yDelta);
} else if (mMode == ImageTouchMode.ZOOM && event.getPointerCount() == 2) {
float newDist = spacing(event);
mMatrix.set(mSavedMatrix);
if (newDist > 10f) {
float scale = newDist / mOldDist;
Log.d(TAG, "Scale to " + scale);
mMatrix.postScale(scale, scale, mMidPoint.x, mMidPoint.y);
}
if (mLastTouchEvent != null) {
float newRot = rotation(event);
float r = newRot - mRotationDegrees;
mMatrix.postRotate(r, getMeasuredWidth() / 2,
getMeasuredHeight() / 2);
}
}
break;
}
// Perform the transformation
setImageMatrix(mMatrix);
return true; // indicate event was handled
}
private boolean hitTestInImageMatrix(MotionEvent event) {
float[] values = new float[9];
mMatrix.getValues(values);
float globalX = values[Matrix.MTRANS_X];
float globalY = values[Matrix.MTRANS_Y];
float width = values[Matrix.MSCALE_X] * getDrawable().getIntrinsicWidth();
float height = values[Matrix.MSCALE_Y] * getDrawable().getIntrinsicHeight();
float x = event.getX();
float y = event.getY();
if (x > globalX && x < (globalX + width) && y > globalY && y <
(globalY + height)) {
Log.d(TAG, "Hit test inside!");
return true;
} else {
Log.d(TAG, "Hit test outside");
return false;
}
}
This works pretty good initially, but as soon as the image is rotated to some degree the hit test no longer works correctly.
How could I correctly detect that the touch event happens inside the transformed matrix after rotation?
Related
I want to limit drag and drop of imageView to not goes out of screen, i don't know how do that, specially when imageView is zoomed, how can i keep imageView in the screen when it's zoomed or not?
here is my code:
/**
* Apply drag zoom to image
*
* #param imageToEdit
* #param mActivity
*/
public static void setOntoucheListner(ImageView imageToEdit, Activity mActivity, final ImageView imageMask) {
// Calcul pourcentage du min image
float ratio1 = imageToEdit.getWidth() / imageMask.getWidth();
float ratio2 = imageToEdit.getHeight() / imageMask.getHeight();
if (ratio1 < 1 && ratio2 < 1)
ZOOM_MIN = 1;
else
ZOOM_MIN = Math.min(ratio1, ratio2);
Display display = mActivity.getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
screenWidth = size.x;
screenHeight = size.y;
matrix = new Matrix();
savedMatrix = new Matrix();
startPoint = new PointF();
midPoint = new PointF();
// imageToEdit.setImageMatrix(new Matrix());
/** * set on touch listner on image */
imageToEdit.setOnTouchListener(new View.OnTouchListener() {
private float savedTranslateX = 0;
private float savedTranslateY = 0;
#Override
public boolean onTouch(View v, MotionEvent event) {
ImageView view = (ImageView) v;
System.out.println("matrix=" + savedMatrix.toString());
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
startPoint.set(event.getX(), event.getY());
mode = DRAG;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(midPoint, event);
mode = ZOOM;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
imageMask.getTop();
imageMask.getTop();
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - startPoint.x, event.getY() - startPoint.y);
mode = DRAG;
} else if (mode == ZOOM) {
float newDist = spacing(event);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = newDist / oldDist;
matrix.postScale(scale, scale, midPoint.x, midPoint.y);
}
}
break;
}
float[] f = new float[9];
matrix.getValues(f);
float scaleX = f[Matrix.MSCALE_X];
float scaleY = f[Matrix.MSCALE_Y];
if (mode == ZOOM) {
if (scaleX <= ZOOM_MIN)
matrix.postScale((ZOOM_MIN) / scaleX, (ZOOM_MIN) / scaleY, midPoint.x, midPoint.y);
else if (scaleX >= ZOOM_MAX)
matrix.postScale((ZOOM_MAX) / scaleX, (ZOOM_MAX) / scaleY, midPoint.x, midPoint.y);
else {
view.setImageMatrix(matrix);
}
} else {
view.setImageMatrix(matrix);
}
return true;
}
#SuppressLint("FloatMath")
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) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
});
}
}
Thank's a lot for your responses
I solved my problem, when user drap imageView out of bounds and release his fingers, i replace imageView on the last valid places so i complete case MotionEvent.ACTION_POINTER_UP like this: My limit here is not the screen but another ImageView,
case MotionEvent.ACTION_POINTER_UP:
matrix.getValues(values);
translateX = values[Matrix.MTRANS_X];
translateY = values[Matrix.MTRANS_Y];
Log.d("####### actualWidthImageToEdit"
+ actualWidthImageToEdit);
Log.d("####### translateX" + translateX);
Log.d("####### imageMask.getRight()" + imageMask.getRight());
// After User release fingers from screen we test if image
// is on a valid position if not we replace it in the last
// valid position
if (mode == DRAG || mode == DEZOOM) {
if (
// Limit Left, Move left to right
translateX > imageMask.getLeft()
// Limit Button, from top to buttom
|| translateY > imageMask.getTop()
// left to right
|| actualWidthImageToEdit
- imageMask.getRight() + translateX < 0
// Limit Top, from buttom to top
|| actualHeightImageToEdit
- imageMask.getBottom() + translateY < 0
) {
matrix = new Matrix(savedMatrix);
view.setImageMatrix(matrix);
view.invalidate();
}
}
I have already searched alot around here but haven't found a solution yet. So the thing is , I have a image 3000*3000 px, I set it to scale type matrix. Now I have only the left corner showing of the image. Now I don't want people to zoom in at this stage, only zoom out to a maximum of 'x' (Still have to see how much).
It's the imageview "kaart" that has to be zoomed.
question : How to let people only zoom out in the beginning and don't let them pass x ?and afterwards, don't let them zoom in more than the original size
i've tried with negative values , but that didn't work
Here is my code:
// These matrices will be used to move and zoom image
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
// max and min zoom
//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));
// 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 start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
String savedItemClicked;
ImageView view;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.kaart);
view = (ImageView) findViewById(R.id.kaart);
view.setOnTouchListener(this);
}
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
ImageView view = (ImageView) v;
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:
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);
}
}
break;
}
limitZoom(matrix);
limitDrag(matrix);
view.setImageMatrix(matrix);
return true;
}
#SuppressWarnings("deprecation")
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());
}
/** Determine the space between the first two fingers */
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);
}
/** Calculate the mid point of the first two fingers */
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);
}
}
Hope someone can help me. I would really apreciate it.
EDIT
I have added 2 functions i found somewhere.
private void limitZoom(Matrix m) {
float[] values = new float[9];
m.getValues(values);
float scaleX = values[Matrix.MSCALE_X];
float scaleY = values[Matrix.MSCALE_Y];
if(scaleX > MAX_ZOOM) {
scaleX = MAX_ZOOM;
} else if(scaleX < MIN_ZOOM) {
scaleX = MIN_ZOOM;
}
if(scaleY > MAX_ZOOM) {
scaleY = MAX_ZOOM;
} else if(scaleY < MIN_ZOOM) {
scaleY = MIN_ZOOM;
}
values[Matrix.MSCALE_X] = scaleX;
values[Matrix.MSCALE_Y] = scaleY;
m.setValues(values);
}
and
private void limitDrag(Matrix m) {
float[] values = new float[9];
m.getValues(values);
float transX = values[Matrix.MTRANS_X];
float transY = values[Matrix.MTRANS_Y];
float scaleX = values[Matrix.MSCALE_X];
float scaleY = values[Matrix.MSCALE_Y];
ImageView iv = (ImageView)findViewById(R.id.kaart);
Rect bounds = iv.getDrawable().getBounds();
int viewWidth = getResources().getDisplayMetrics().widthPixels;
int viewHeight = getResources().getDisplayMetrics().heightPixels;
int width = bounds.right - bounds.left;
int height = bounds.bottom - bounds.top;
float minX = (-width + 20) * scaleX;
float minY = (-height + 20) * scaleY;
if(transX > (viewWidth - 20)) {
transX = viewWidth - 20;
} else if(transX < minX) {
transX = minX;
}
if(transY > (viewHeight - 80)) {
transY = viewHeight - 80;
} else if(transY < minY) {
transY = minY;
}
values[Matrix.MTRANS_X] = transX;
values[Matrix.MTRANS_Y] = transY;
m.setValues(values);
}
I have to call these functions right after the switch case and just before is set the imagematrix on my view. (I have added this to my previous code here above)
maybe this isn't the best solution , but it works .
If I understand your code, you keep saving the matrix as a way to remember what was the state of the zoom and scroll (which could be done by one matrix alone, but maybe you're doing other manipulations).
This way, every action effects are relative to the last state, and it's difficult to set an absolute limit to the zoom (and scroll too): to get their absolute values, you'd have to call matrix.getValues() and pick the values from the array it returns.
Try instead saving the current x-scroll, y-scroll and zoom, and at every action check if their updated values (that now remain absolute) would be inside your limits; if so actually update them, then reset the matrix and set the new scroll/zoom values.
(also, consider the use of GestureDetector and ScaleGestureDetector)
I need to drag and zoom an image. Here is my code ...
//instance variables
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
//OnTouchListener for imageview
OnTouchListener touchAction = new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
ImageView i = (ImageView)v;
dragAndZoom(i, event);
return true;
}
};
//performing drag&zoom operations
private void dragAndZoom(View v, MotionEvent event)
{
ImageView view = (ImageView) v;
view.setScaleType(ImageView.ScaleType.MATRIX);
float scale;
// 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());
mode = DRAG;
break;
case MotionEvent.ACTION_UP: // first finger lifted
case MotionEvent.ACTION_POINTER_UP: // second finger lifted
mode = NONE;
break;
case MotionEvent.ACTION_POINTER_DOWN: // first and second finger down
oldDist = spacing(event);
if (oldDist > 5f)
{
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
}
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)
{
// pinch zooming
float newDist = spacing(event);
if (newDist > 5f)
{
matrix.set(savedMatrix);
scale = newDist / oldDist;
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
}
view.setImageMatrix(matrix); // display the transformation on screen
}
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)
{
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
It works okay. but sometimes the image is going out of screen boundaries on touch of it. How can i keep the image in UI all the times? Please help me. Thanks in advance.
private void limitDrag(Matrix m, ImageView view) {
float[] values = new float[9];
m.getValues(values);
float transX = values[Matrix.MTRANS_X];
float transY = values[Matrix.MTRANS_Y];
float scaleX = values[Matrix.MSCALE_X];
float scaleY = values[Matrix.MSCALE_Y];
Rect bounds = view.getDrawable().getBounds();
int viewWidth = getResources().getDisplayMetrics().widthPixels;
int viewHeight = getResources().getDisplayMetrics().heightPixels;
if(viewHeight<=480)
{
_y_up=0;
}
if(viewHeight>480&&viewHeight<980)
{
_y_up=140;
}
int width = bounds.right - bounds.left;
int height = bounds.bottom - bounds.top;
int __width=width;
int __height=height;
width = viewWidth / 2;
height = viewHeight / 2;
//height = 200 ;
float minX = (-width) ;//* scaleX;
float minY = (-height) ;//* scaleY;
if ((transX) > (viewWidth)) {
//_x_left
transX = viewWidth;
} else if (transX < minX) {
transX = minX;
}
if ((-transX) > (viewWidth)) {
// _x_right
transX = -(viewWidth);
} else if (-transX < minX) {
transX = -(minX+30);
}
if ((transY) > (viewHeight)) {
// _y_up
transY =( viewHeight);
} else if (transY < minY) {
transY = (minY+_y_up);
}
if ((-transY) > (viewHeight)) {
// _y_down
transY = -(viewHeight);
} else if (-transY < minY) {
transY = -(minY+170);
}
values[Matrix.MTRANS_X] = transX;
values[Matrix.MTRANS_Y] = transY;
m.setValues(values);
}
Call this function limitDrag(matrix,view) just above your view.setImageMatrix(matrix) to restrict the movement inside the screen
Note:- IM doing some ugly hardcoded calculation inside it. you can change it according to your need.Just run this and check, remember its not the best solution still something is better than nothing.Happy coding!
I had implemented an image view with the zoom and drag functionalities.I am using matrix for the zoom and drag functionality.But my problem is that I cant set my minimum and maximum zoom level and the drag space limit.can any on e tell me how I can do that.
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) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
private float spacing(PointF start,PointF end)
{
float x = end.x- start.x;
float y = end.y -start.y;
return FloatMath.sqrt(x * x + y * y);
}
#Override
public boolean onTouch(View v, MotionEvent event)
{
ImageView view = (ImageView) v;
view.setScaleType(ImageView.ScaleType.MATRIX);
float scale;
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_UP:
if(mode==DRAG)
{
PointF end=new PointF();
end.set(event.getX(), event.getY());
Log.d("Fling", "Inside the Action Key UP"+spacing(start, end));
float []x = new float[9],org=new float[9];
matrix.getValues(x);
orgMatrix.getValues(org);
Log.d("Fling", "matrixValue"+matrix);
Log.d("Fling", "OrgmatrixValue"+orgMatrix);
float matrixSizex=x[Matrix.MSCALE_X];
float matrixSizey=x[Matrix.MSCALE_Y];
float matrixOrgSizex=org[Matrix.MSCALE_X];
float matrixOrgSizey=org[Matrix.MSCALE_Y];
if(Math.abs(matrixOrgSizex-matrixSizex)<0.17f&&Math.abs(matrixOrgSizey-matrixSizey)<0.17f)
{
Log.d("Fling", "Current Size is equal");
if(spacing(start, end)>30.f)
{
if((start.x>end.x+30)&&(Math.abs(start.y-end.y)<50.0f))
{
Log.d("Fling", "Is From Right To left");
loadedimage.setImageMatrix(orgMatrix);
leftSwipe();
view.setScaleType(ImageView.ScaleType.FIT_XY);
}
else if((end.x>start.x+30)&&(Math.abs(end.y-start.y)<50.0f))
{
Log.d("Fling", "Is From Left To Right");
loadedimage.setImageMatrix(orgMatrix);
rightSwipe();
view.setScaleType(ImageView.ScaleType.FIT_XY);
}
}
}
}
case MotionEvent.ACTION_POINTER_UP: //second finger lifted
mode = NONE;
Log.d(TAG, "mode=NONE" );
break;
case MotionEvent.ACTION_POINTER_DOWN: //second finger down
oldDist = spacing(event);
Log.d(TAG, "oldDist=" + oldDist);
if (oldDist > 5f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
Log.d(TAG, "mode=ZOOM" );
}
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
//movement of first finger
PointF end=new PointF();
end.set(event.getX(), event.getY());
Log.d("Fling", "Inside the Action Key UP"+spacing(start, end));
float []x = new float[9],org=new float[9];
matrix.getValues(x);
orgMatrix.getValues(org);
Log.d("Fling", "matrixValue"+matrix);
Log.d("Fling", "OrgmatrixValue"+orgMatrix);
float matrixSizex=x[Matrix.MSCALE_X];
float matrixSizey=x[Matrix.MSCALE_Y];
float matrixOrgSizex=org[Matrix.MSCALE_X];
float matrixOrgSizey=org[Matrix.MSCALE_Y];
if(Math.abs(matrixOrgSizex-matrixSizex)>=0.17f&&Math.abs(matrixOrgSizey-matrixSizey)>=0.17f)
{
matrix.set(savedMatrix);
if (view.getLeft() >= 0)
{
matrix.postTranslate(event.getX() - start.x, event.getY() - start.y);
}
}
}
else if (mode == ZOOM) { //pinch zooming
float newDist = spacing(event);
Log.d(TAG, "newDist=" + newDist);
if (newDist > 5f) {
matrix.set(savedMatrix);
scale = newDist / oldDist; //thinking i need to play around with this value to limit it**
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
}
// Perform the transformation
view.setImageMatrix(matrix);
return true; // indicate event was handled
}
My Sample code is here can any one help me in setting minimum and maximum zoom and drag level.I also have problem when I touch in the image view it automatically get zoomed when converted to the matrix I cant make it stay fit in the device screen.I am totally stuck here........
To restrict zooming I compare the zoomed matrix with the identity matrix and don't assign it to my ImageView if it's smaller than the identity matrix, in which case I reset the scaled matrix back to the identity matrix. I'm using Mono for Android but I guess it will be almost the same in Java:
//check that zoom is not too small
if (Utils.SmallerThanIdentity(matrix))
{
ResetView(v);
}
Where SmallerThanIdentity is implemented:
public static bool SmallerThanIdentity(Android.Graphics.Matrix m)
{
float[] values = new float[9];
m.GetValues(values);
return ((values[0] < 1.0) || (values[4] < 1.0) || (values[8] < 1.0));
}
And here's ResetView. I have Java code for that:
public void resetView(View v)
{
ImageView view = (ImageView)v;
matrix = new Matrix();
view.setScaleType(ImageView.ScaleType.MATRIX);
view.setImageMatrix(matrix);
}
Regarding scroll, I use the ShouldScroll method below before translating the matrix to the area where I want to restrict the scrolling.
private bool ShouldScroll(Android.Graphics.Matrix matrix)
{
float[] values = new float[9];
matrix.GetValues(values);
float[] oldValues = new float[9];
oldMatrix.GetValues(oldValues);
float zoomPercentX = values[0] / oldValues[0];
float zoomPercentY = values[4] / oldValues[4];
float tmpW = -(this.Drawable.IntrinsicWidth / 2) * zoomPercentX;
float tmpH = -(this.Drawable.IntrinsicHeight / 2) * zoomPercentY;
return (values[2] < 0.0f) && (values[2] > tmpW) && //horizontal coordinates
(values[5] < 0.0f) && (values[5] > tmpH); //vertical coordinates
}
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
android imageView: setting drag and pinch zoom parameters
I am very new to android .. I have an image view in my layout .. I want to enable the zoom in and zoom out for the image coming from this image view .. zoom should be done on two finger touch ..
can anyone tell me how to accomplish this,
Thanks ,
Raj
see this
private static final String TAG = "Touch";
//These matrices will be used to move and zoom image
Matrix matrix = new Matrix();
Matrix savedMatrix = 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;
static final int DRAW =3;
int mode = NONE;
// Remember some things for zooming
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
// Limit zoomable/pannable image
private float[] matrixValues = new float[9];
private float maxZoom;
private float minZoom;
private float height;
private float width;
private RectF viewRect;
/////////************ touch events functions **************////////////////////
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if(hasFocus){ init(); }
}
private void init() {
maxZoom = 4;
minZoom = 0.25f;
height = myimage.getDrawable().getIntrinsicHeight()+20;
width = myimage.getDrawable().getIntrinsicWidth()+20;
viewRect = new RectF(0, 0, myimage.getWidth()+20, myimage.getHeight()+20);
}
/////////************touch events for image Moving, panning and zooming ***********///
public boolean onTouch(View v, MotionEvent event) {
// Dump touch event to log
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:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
Log.d(TAG, "mode=NONE");
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAW){ onTouchEvent(event);}
if (mode == DRAG) {
///code for draging..
}
else if (mode == ZOOM) {
float newDist = spacing(event);
Log.d(TAG, "newDist=" + newDist);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = newDist / oldDist;
matrix.getValues(matrixValues);
float currentScale = matrixValues[Matrix.MSCALE_X];
// limit zoom
if (scale * currentScale > maxZoom) {
scale = maxZoom / currentScale;
}else if(scale * currentScale < minZoom){
scale = minZoom / currentScale;
}
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
}
myimage.setImageMatrix(matrix);
return true; // indicate event was handled
}
//*******************Determine the space between the first two fingers
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);
}
//************* Calculate the mid point of the first two fingers
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);
}
}