I am trying to create an app where user can touch an image and zoom using multi touch gesture. I searched over the net and found few solutions to do so. I even implemented those but all my efforts are in vain. First my code was not able to detect multitouch for which i realized that we also need to add MotionEvent.ACTION_MASK in switch case. Then now when i try to zoom the using multi touch no effect takes place. Please correct me.
TIA.
OnTouchListener onTouchListener = new OnTouchListener() {
int prevX,prevY;
float scale;
float mCurrentScale = 1.0f;
#Override
public boolean onTouch(View v, MotionEvent event) {
//view.setScaleType(ImageView.ScaleType.MATRIX);
scaleGestureDetector.onTouchEvent(event);
ImageView view = (ImageView) v;
v.bringToFront();
final RelativeLayout.LayoutParams par=(RelativeLayout.LayoutParams)v.getLayoutParams();
switch(event.getAction() & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_UP:
par.topMargin+=(int)event.getRawY()-prevY;
par.leftMargin+=(int)event.getRawX()-prevX;
v.setLayoutParams(par);
break;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
lastEvent = null;
break;
case MotionEvent.ACTION_DOWN:
prevX=(int)event.getRawX();
prevY=(int)event.getRawY();
par.bottomMargin=-2*view.getHeight();
par.rightMargin=-2*view.getWidth();
v.setLayoutParams(par);
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
Log.d("hi","outside if DRAG");
mode = DRAG;
lastEvent = null;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
Log.d("hi","Checking");
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
}
lastEvent = new float[4];
lastEvent[0] = event.getX(0);
lastEvent[1] = event.getX(1);
lastEvent[2] = event.getY(0);
lastEvent[3] = event.getY(1);
d = rotation(event);
break;
case MotionEvent.ACTION_MOVE:
if(mode == DRAG){
par.topMargin+=(int)event.getRawY()-prevY;
prevY=(int)event.getRawY();
par.leftMargin+=(int)event.getRawX()-prevX;
prevX=(int)event.getRawX();
v.setLayoutParams(par);
}
if (mode == ZOOM) {
float newDist = spacing(event);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = (newDist / oldDist);
matrix.postScale(scale, scale, mid.x, mid.y);
Log.e("hi", "TEsting");
}
if (lastEvent != null && event.getPointerCount() == 3) {
newRot = rotation(event);
float r = newRot - d;
float[] values = new float[9];
matrix.getValues(values);
float tx = values[2];
float ty = values[5];
float sx = values[0];
float xc = (v.getWidth() / 2) * sx;
float yc = (v.getHeight() / 2) * sx;
matrix.postRotate(r, tx + xc, ty + yc);
}
}
break;
}
//ImageView view = (ImageView) v;
view.setImageMatrix(matrix);
v.invalidate();
return true;
}
};
You may need to use the piece of code:
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class MultiTouchActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
TouchImageView img = new TouchImageView(this);
img.setImageResource(R.drawable.ice_age_2);
img.setMaxZoom(4f);
setContentView(img);
}
}
For reference use the link
here
Related
I'm working on application where i implemented zoom feature but when i tries to pinch for zoom, it is being very fast zoom. How can i slow down or normalize this zoom feature ?
It's pleasure if any can help.
Here is the intialization of used variable in zooming
private static final float MIN_ZOOM = 1f;
private static final float MAX_ZOOM = 4f;
private float scaleAll = 1;
The code in OnTouchListener for zooming a view in my custom view is,
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
if (mode != MOVING_MODE) {
float[] v = new float[9];
matrix.getValues(v);
// translation
float mScalingFactor = v[Matrix.MSCALE_X];
RectF r = new RectF();
matrix.mapRect(r);
// mScalingFactor shall contain the scale/zoom factor
float scaledX = (x - r.left);
float scaledY = (y - r.top);
scaledX /= mScalingFactor;
scaledY /= mScalingFactor;
x = scaledX;
y = scaledY;
}
int maskedAction = event.getActionMasked();
switch (maskedAction) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
touchMode = DRAG;
if (mode == MOVING_MODE) {
DownPT.x = event.getX();
DownPT.y = event.getY();
}
invalidate();
break;
case MotionEvent.ACTION_MOVE:
if (touchMode == DRAG) {
if (mode == MOVING_MODE) {
PointF mv = new PointF(event.getX() - DownPT.x, event.getY() - DownPT.y);
matrix.postTranslate(mv.x, mv.y);
DownPT.x = event.getX();
DownPT.y = event.getY();
}
invalidate();
} else if (touchMode == ZOOM && mode == MOVING_MODE) {
// pinch zooming
float newDist = spacing(event);
if (newDist > 10f) {
scale = newDist / oldDist; //setting the scaling of the matrix...
// normalize scale
if (scale * scaleAll > MAX_ZOOM) {
scale = MAX_ZOOM / scaleAll;
}
if (scale * scaleAll < MIN_ZOOM) {
scale = MIN_ZOOM / scaleAll;
}
scaleAll *= scale;
//if scale > 1 means zoom in
// if scale < 1 means zoom out
matrix.postScale(scale, scale, mid.x, mid.y);
}
invalidate();
}
break;
case MotionEvent.ACTION_UP:
if (mode == ERASE_MODE || mode == UNERASE_MODE) {
touch_up();
is_from_init = false;
temt_x = event.getX();
temp_y = event.getY();
Log.d(TAG, "add to stack");
addToStack(false);
}
invalidate();
break;
case MotionEvent.ACTION_POINTER_UP: // second finger lifted
touchMode = NONE;
Log.d(TAG, "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);
touchMode = ZOOM;
Log.d(TAG, "mode=ZOOM");
}
break;
}
return true;
}
I am trying to develop draw something on image when image zoom in my project but when zoom then it will be create some offset between touch and drawing but without zoom it is working perfect. For example.
Code for image zoom:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.concat(matrix);
....
}
#Override
public boolean onTouch(View v, MotionEvent event) {
ImageView view = (ImageView) v;
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
mode = DRAG;
lastEvent = null;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
}
lastEvent = new float[4];
lastEvent[0] = event.getX(0);
lastEvent[1] = event.getX(1);
lastEvent[2] = event.getY(0);
lastEvent[3] = event.getY(1);
d = rotation(event);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
lastEvent = null;
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 && event.getPointerCount() == 2) {
float newDist = spacing(event);
matrix.set(savedMatrix);
if (newDist > 10f) {
float scale = newDist / oldDist;
matrix.postScale(scale, scale, mid.x, mid.y);
}
if (lastEvent != null) {
float newRot = rotation(event);
float r = newRot - d;
matrix.postRotate(r, view.getMeasuredWidth() / 2, view.getMeasuredHeight() / 2);
}
}
break;
}
invalidate();
return true;
}
Code for drawing:
#Override
public boolean onTouch(View view, MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchStart(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touchMove(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touchEnd();
invalidate();
break;
}
return true;
}
private void touchMove(float x, float y) {
float f1 = Math.abs(x - mX);
float f2 = Math.abs(y - mY);
if ((f1 >= 4.0F) || (f2 >= 4.0F)) {
path.quadTo(mX, mY,
(x + mX) / 2.0F,
(y + mY) / 2.0F);
mX = x;
mY = y;
}
}
private void touchStart(float x, float y) {
path.reset();
path.moveTo(x, y);
blurView.pathList.add(path);
blurView.strokeWidthList.add(strokeWidth);
mX = x;
mY = y;
}
private void touchEnd() {
path.lineTo(mX, mY);
path = new Path();
}
can any one help me for how to handle scale factor or how to remove image zoom scale factor into the finger touch.
You usually store the scale factor, and multiplies many of your coordinates handle system by its value.
Simply as that.
I have one main and big ImageView and 4-5 small ImageView on it. The small ImageView can utilize zoom-in-out, drag to change place, and rotate, all by an onTouchEvent that I built in a custom ImageView.
Since use of onTouch event for dragging (moving) ImageView, I cant use OnDragListener for deleting the small ImageView. I want to delete by moving to corner of the screen or over a specific button.
Please help me find a solution.
public boolean onTouchEvent(MotionEvent event) {
this.setScaleType(ImageView.ScaleType.MATRIX);
float scale;
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("amin", "mode=DRAG");
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
}
lastEvent = new float[4];
lastEvent[0] = event.getX(0);
lastEvent[1] = event.getX(1);
lastEvent[2] = event.getY(0);
lastEvent[3] = event.getY(1);
d = rotation(event);
break;
case MotionEvent.ACTION_UP: //first finger lifted
case MotionEvent.ACTION_POINTER_UP: //second finger lifted
mode = NONE;
Log.d("amin", "mode=NONE" );
break;
case MotionEvent.ACTION_MOVE:
if (mode == ZOOM && event.getPointerCount() == 2) {
float newDist = spacing(event);
matrix.set(savedMatrix);
if (newDist > 10f) {
scale = newDist / oldDist;
matrix.postScale(scale, scale, mid.x, mid.y);
}
if (lastEvent != null) {
newRot = rotation(event);
float r = newRot - d;
matrix.postRotate(r, this.getMeasuredWidth() / 2,
this.getMeasuredHeight() / 2);
}
}else{
mode = DRAG;
// matrix.set(savedMatrix);
//matrix.postTranslate(event.getX() - start.x, event.getY()-start.y);
//this.layout((int)(start.x- (this.getWidth())),(int)(start.y- (this.getHeight())),(int) start.x, (int) start.y);
RelativeLayout.LayoutParams layoutPrarms = (RelativeLayout.LayoutParams)this.getLayoutParams();
int left = layoutPrarms.leftMargin + (int)(event.getX() - start.x);
int top = layoutPrarms.topMargin + (int)(event.getY() - start.y);
layoutPrarms.leftMargin = left;
layoutPrarms.topMargin = top;
this.setLayoutParams(layoutPrarms);
Log.d("amin", "mode=Drag" );
}
break;
}
// Perform the transformation
this.setImageMatrix(matrix);
return true;
}
My requirent is to generate multiple images dynamically and perform all operation on it like drag, drop, scale, rotate.I want every image can move on whole layout. but the problem is in which area 1 image can move another image can not move. I want user can any time select any image and any image can move any where in the layout.
My code to generate Image randomly inside onclick
LinearLayout.LayoutParams imParams = new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
imge = new ImageView(MultiTouch.this);
imge.setImageResource(R.drawable.ic_launcher);
imge.setScaleType(ScaleType.MATRIX);
imge.buildDrawingCache();
BitmapDrawable drawable = (BitmapDrawable) imge.getDrawable();
Bitmap bitmap = drawable.getBitmap();
imge.setId(i++);
ll.addView(imge, imParams);
My ontouch listnner :
public boolean onTouch(View v, MotionEvent event) {
// Toast.makeText(MultiTouch.this, "onTouch", Toast.LENGTH_LONG).show();
ImageView view = (ImageView) v;
boolean defaultResult = v.onTouchEvent(event);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
mode = DRAG;
lastEvent = null;
System.out.println("ACTION_DOWN " );
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
}
lastEvent = new float[4];
lastEvent[0] = event.getX(0);
lastEvent[1] = event.getX(1);
lastEvent[2] = event.getY(0);
lastEvent[3] = event.getY(1);
d = rotation(event);
System.out.println("ACTION_POINTER_DOWN " );
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
lastEvent = null;
v.clearFocus();
System.out.println("ACTION_POINTER_UP " );
return false;
// break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
matrix.set(savedMatrix);
float dx = event.getX() - start.x;
float dy = event.getY() - start.y;
matrix.postTranslate(dx, dy);
} else if (mode == ZOOM) {
float newDist = spacing(event);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = (newDist / oldDist);
matrix.postScale(scale, scale, mid.x, mid.y);
}
if (lastEvent != null && event.getPointerCount() == 2) {
newRot = rotation(event);
float r = newRot - d;
float[] values = new float[9];
matrix.getValues(values);
float tx = values[2];
float ty = values[5];
float sx = values[0];
float xc = (view.getWidth() / 2) * sx;
float yc = (view.getHeight() / 2) * sx;
// matrix.postRotate(r, tx + xc, ty + yc);
matrix.postRotate(r, view.getWidth() / 2,
view.getHeight() / 2);
}
}
System.out.println("ACTION_MOVE " );
break;
default:
return defaultResult;
}
view.setImageMatrix(matrix);
return super.onTouchEvent(event);
}
and my xml code :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/frmlayut"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="Button" />
<LinearLayout
android:id="#+id/ll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/button1"
android:background="#drawable/backgrd"
android:orientation="vertical" >
</LinearLayout>
</RelativeLayout>
can any one tell me How to move any image any time across whole layout? Do i need to make layers, If yes how to do it.
i want to rotate and scale the image on multi touch event,
i am able to drag, scale the image but i can't understand the rotation of image.
i am facing problem so please help me asap.
my code is there
public class Touch extends Activity implements OnTouchListener {
private static final String TAG = "Touch";
// These matrices will be used to move and zoom image
Matrix matrix = new Matrix();
Matrix matrix1 = new Matrix();
Matrix savedMatrix = new Matrix();
Matrix savedMatrix2 = 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;
float oldscale =0;
// Remember some things for zooming
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageView view = (ImageView) findViewById(R.id.imageView2);
view.setOnTouchListener(this);
ImageView view1 = (ImageView) findViewById(R.id.imageView2);
view1.setOnTouchListener(this);
// ...
// Work around a Cupcake bug
matrix.setTranslate(1f, 1f);
matrix1.setTranslate(1f, 1f);
view.setImageMatrix(matrix);
view1.setImageMatrix(matrix1);
}
#Override
public boolean onTouch(View v, MotionEvent rawEvent) {
WrapMotionEvent event = WrapMotionEvent.wrap(rawEvent);
// ...
ImageView view = (ImageView) v;
// Dump touch event to log
dumpEvent(event);
// Handle touch events here...
double r = Math.atan2(event.getX() - 400 / 2,
400 / 2 - event.getY());
int rotation = (int) Math.toDegrees(r);
float newRot = new Float(rotation);
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:
matrix.postRotate(15);
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);
Log.e("scale | mid.x | mid.y", scale + " " +mid.x + " " + mid.y);
}
}
break;
}
view.setImageMatrix(matrix);
return true; // indicate event was handled
}
/** Show an event in the LogCat view, for debugging */
private void dumpEvent(WrapMotionEvent 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(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);
}
}
so please provide me exact solution for this problem.
float[] lastEvent = null;
float d = 0f;
float newRot = 0f;
#Override
public boolean onTouch(View v, MotionEvent event) {
ImageView view = (ImageView) v;
// 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());
if (Constant.TRACE) Log.d(TAG, "mode=DRAG");
mode = DRAG;
lastEvent = null;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
if (Constant.TRACE) Log.d(TAG, "mode=ZOOM");
lastEvent = new float[4];
lastEvent[0] = event.getX(0);
lastEvent[1] = event.getX(1);
lastEvent[2] = event.getY(0);
lastEvent[3] = event.getY(1);
d = rotation(event);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
lastEvent = null;
if (Constant.TRACE) 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 && event.getPointerCount()==2) {
float newDist = spacing(event);
if (Constant.TRACE) Log.d(TAG, "Count=" + event.getPointerCount());
if (Constant.TRACE) Log.d(TAG, "newDist=" + newDist);
matrix.set(savedMatrix);
if (newDist > 10f) {
float scale = newDist / oldDist;
matrix.postScale(scale, scale, mid.x, mid.y);
}
if (lastEvent!=null){
newRot = rotation(event);
if (Constant.TRACE) Log.d("Degreeeeeeeeeee", "newRot="+(newRot));
float r = newRot-d;
matrix.postRotate(r, imgView.getMeasuredWidth()/2, imgView.getMeasuredHeight()/2);
}
}
break;
}
view.setImageMatrix(matrix);
return true; // indicate event was handled
}
/** Determine the degree between the first two fingers */
private float rotation(MotionEvent event) {
double delta_x = (event.getX(0) - event.getX(1));
double delta_y = (event.getY(0) - event.getY(1));
double radians = Math.atan2(delta_y, delta_x);
if (Constant.TRACE) Log.d("Rotation ~~~~~~~~~~~~~~~~~", delta_x+" ## "+delta_y+" ## "+radians+" ## "
+Math.toDegrees(radians));
return (float) Math.toDegrees(radians);
}
Try this code, but remember some old phone have problem with rotation..