I have an ImageView in a layout and set OnTouchListener on ImageView to drag the ImageView. It\'s working perfectly. My problem is how can I prevent from move ImageView to out o
I used the answer from Benito Bertoli and modified the ACTION_MOVE code changing minor and major sign to make image zoom and drag for image zoomed
here´s the code
private static final float MIN_ZOOM = 1f;
private static final float MAX_ZOOM = 2.5f;
public boolean onTouch(View v, MotionEvent event) {
ImageView view = (ImageView) v;
view.setScaleType(ImageView.ScaleType.MATRIX);
// 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_UP: //first finger lifted
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 > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
Log.d(TAG, "mode=ZOOM" );
}
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
//matrix.set(savedMatrix);
//matrix.postTranslate(event.getX() - start.x, event.getY() - start.y);
matrix.set(savedMatrix);
matrix.getValues(matrixValues);
matrixX = matrixValues[2];
matrixY = matrixValues[5];
width = matrixValues[0] * (view.getDrawable().getIntrinsicWidth());
height = matrixValues[4] * (view.getDrawable().getIntrinsicHeight());
dx = event.getX() - start.x;
dy = event.getY() - start.y;
//if image will go outside left bound
if (matrixX + dx > 0){
Log.e("dx","lef bound " + dx);
dx = -matrixX;
}
//if image will go outside right bound
if(matrixX + dx + width < view.getWidth()){
dx = view.getWidth() - matrixX - width;
}
//if image will go oustside top bound
if (matrixY + dy > 0){
dy = -matrixY;
}
//if image will go outside bottom bound
if(matrixY + dy + height < view.getHeight()){
dy = view.getHeight() - matrixY - height;
}
matrix.postTranslate(dx, dy);
}
else if (mode == ZOOM) {
Float newDist = spacing(event);
Log.d(TAG, "newDist=" + newDist);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = newDist / oldDist;
float[] values = new float[9];
matrix.getValues(values);
float currentScale = values[Matrix.MSCALE_X];
if(scale * currentScale > MAX_ZOOM)
scale = MAX_ZOOM / currentScale;
else if (scale * currentScale < MIN_ZOOM)
scale = MIN_ZOOM / currentScale;
matrix.postScale(scale, scale, mid.x, mid.y);
}
break;
}
} //perform the transformation.
view.setImageMatrix(matrix);
return true; // indicate event was handled
}
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);
}
return drawable;
}
Android documentation says:
It is possible to retrieve the location of a view by invoking the methods getLeft() and getTop(). The former returns the left, or X, coordinate of the rectangle representing the view. The latter returns the top, or Y, coordinate of the rectangle representing the view. These methods both return the location of the view relative to its parent.
In addition, several convenience methods are offered to avoid unnecessary computations, namely getRight() and getBottom(). These methods return the coordinates of the right and bottom edges of the rectangle representing the view. For instance, calling getRight() is similar to the following computation: getLeft() + getWidth().
So you can get your image coordinates before moving it,and you can compute measure of movement in your OnTouchListener class.Now if (X coordinate of your image plus horizontal movement that you computed,be greater than device width
or Y coordinate of your image plus vertical movement that you computed,be greater than device height
) your image not move.
I have done this code. when I zoom hen it should not go out of boundry. its working fine.But when it touches cordinate of x=0 and y=0 it do not minimize.
int FLAG=0;
else if (mode == ZOOM) {
float newDistance = spacing(event);
Log.i("new distance ", newDistance+"");
matrix.getValues(matrixValues);
matrixX = matrixValues[2];
matrixY = matrixValues[5];
width = matrixValues[0]
* (((ImageView) view).getDrawable().getIntrinsicWidth());
height = matrixValues[4]
* (((ImageView) view).getDrawable()
.getIntrinsicHeight());
dx = event.getX() - start.x;
dy = event.getY() - start.y;
// if image will go outside left bound
if (matrixX + dx < 0) {
FLAG=1;
}
if (matrixX + dx + width > view.getWidth()) {
FLAG=1;
//dx = view.getWidth() - matrixX - width;
}
// if image will go oustside top bound
if (matrixY + dy < 0) {
FLAG=1;
//dy = -matrixY;
}
// if image will go outside bottom bound
if (matrixY + dy + height > view.getHeight()) {
FLAG=1;
//dy = view.getHeight() - matrixY - height;
}
if (matrixX + dx ==0 || matrixY + dy==0){
FLAG=0;
}
if (newDistance > 10f && FLAG==0) {
matrix.set(savedMatrix);
float scale = newDistance / oldDistance;
float[] values = new float[9];
matrix.getValues(values);
float currentScale = values[Matrix.MSCALE_X];
if (scale * currentScale > MAX_ZOOM)
scale = MAX_ZOOM / currentScale;
else if (scale * currentScale < MIN_ZOOM)
scale = MIN_ZOOM / currentScale;
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
Add the following parameters to the Touch
class:
private float dx; // postTranslate X distance
private float dy; // postTranslate Y distance
private float[] matrixValues = new float[9];
float matrixX = 0; // X coordinate of matrix inside the ImageView
float matrixY = 0; // Y coordinate of matrix inside the ImageView
float width = 0; // width of drawable
float height = 0; // height of drawable
Modify your code after case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
matrix.set(savedMatrix);
matrix.getValues(matrixValues);
matrixX = matrixValues[2];
matrixY = matrixValues[5];
width = matrixValues[0] * (((ImageView) view).getDrawable()
.getIntrinsicWidth());
height = matrixValues[4] * (((ImageView) view).getDrawable()
.getIntrinsicHeight());
dx = event.getX() - start.x;
dy = event.getY() - start.y;
//if image will go outside left bound
if (matrixX + dx < 0){
dx = -matrixX;
}
//if image will go outside right bound
if(matrixX + dx + width > view.getWidth()){
dx = view.getWidth() - matrixX - width;
}
//if image will go oustside top bound
if (matrixY + dy < 0){
dy = -matrixY;
}
//if image will go outside bottom bound
if(matrixY + dy + height > view.getHeight()){
dy = view.getHeight() - matrixY - height;
}
matrix.postTranslate(dx, dy);
}
We need to create two Rect objects, one is for our view and another for our image according to the view coordinates.
float[] values = new float[9];
matrix.getValues(values);
float globalX = values[Matrix.MTRANS_X];
float globalY = values[Matrix.MTRANS_Y];
float scaleX = values[Matrix.MSCALE_X];
float scaleY = values[Matrix.MSCALE_Y];
Rect viewRect = new Rect(0, 0, viewWidth, viewHeight);
Rect imageRect = new Rect((int) globalX, (int) globalY, Math.round(bitmapWidth * scaleX + globalX),
Math.round(bitmapHeight * scaleY + globalY));
If we want our image be always inside our view, then we check this:
if (!viewRect.contains(imageRect)) {
matrix.set(lastSetMatrix); //return to last saved parameters
}
Sometimes we need our image always be bigger than our view to position a part of the image inside the view, then we can check this:
if (!imageRect.contains(viewRect)) {
matrix.set(lastSetMatrix);
}