I need to click on particular item on the canvas while zooming and moving functionalities also enable for canvas. I can calculate the rectangle position while moving the canvas. There I just calculate the touch movement distance by (CurrenTouchXPosition - StartXPosition).
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
int x = (int) event.getX();
int y = (int) event.getY();
float moveOffsetX = (event.getX() - start.x);
float moveOffsetY = (event.getY() - start.y);
Then,
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
mode = DRAG;
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_UP:
Log.d(TAG, "action up");
secondRectUpperX = secondRectUpperX + moveOffsetX;
secondRectBottomX = secondRectBottomX + moveOffsetX;
secondRectUpperY = secondRectUpperY + moveOffsetY;
secondRectBottomY = secondRectBottomY + moveOffsetY;
This can identify the new canvas position of the rectangle. This works perfectly. I can identify the touch event of particular item while moving the canvas by this logic.
But now i need to calculate the rectangle position relative to the canvas, after zoom the canvas. Whats the maths behind the zooming. If anyone knows please help in this.
Thank you.
Finally I come up with a solution.
I translate my touch position screen coordinates to canvas coordinates.
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
...
break;
case MotionEvent.ACTION_POINTER_DOWN:
...
break;
case MotionEvent.ACTION_UP:
float []m = new float[9];
matrix.getValues(m);
float transX = m[Matrix.MTRANS_X] * -1;
float transY = m[Matrix.MTRANS_Y] * -1;
float scaleX = m[Matrix.MSCALE_X];
float scaleY = m[Matrix.MSCALE_Y];
lastTouchX = (int) ((event.getX() + transX) / scaleX);
lastTouchY = (int) ((event.getY() + transY) / scaleY);
lastTouchX = Math.abs(lastTouchX);
lastTouchY = Math.abs(lastTouchY);
Thanks for Andres Cardenas Pardo's answer here
I could able to get the touch position coordinates according to the canvas coordinates. Since i know the coordinates of my drawn object, i check whether the touch position is within the range of drawn object.
if((lastTouchX>=firstRectUpperX && firstRectBottomX>=lastTouchX) && (lastTouchY>=firstRectUpperY && firstRectBottomY>=lastTouchY)) {
isbtn1Clicked = true;
}
Related
In my application i want to get image x and y coordinates after drag and zoom the image. So I am using the following code.In my xml i have taken relative layout.This is relative layout.
<RelativeLayout
android:id="#+id/image"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="#+id/buttonlayout"
android:layout_marginTop="0dp" >
</RelativeLayout>
In this relative layout i want to drag the image and zoom the image.So that's why I have created Image view programatically and apply the touch listener to that image view.This is the oncreate code.
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.inventory_submit_images_activity);
relImage=(RelativeLayout) findViewById(R.id.image);
imgMarker = new ImageView(this);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT,
RelativeLayout.LayoutParams.FILL_PARENT);
params.leftMargin = 0;
params.topMargin = 0;
relImage.addView(imgMarker, params);
imgMarker.setScaleType(ImageView.ScaleType.MATRIX);
bmdragImage=BitmapFactory.decodeResource(getResources(), R.drawable.image_marker);
height = bmdragImage.getHeight();
width = bmdragImage.getWidth();
imgMarker.setImageBitmap(bmdragImage);
imgMarker.setOnTouchListener(this);
}
And this is the ontouch method and related methods.
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
ImageView view = (ImageView) v;
view.setScaleType(ImageView.ScaleType.MATRIX);
float scale = 0;
layoutParamss = (RelativeLayout.LayoutParams)
v.getLayoutParams();
// Handle touch events here...
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: // first finger down only
x=(int) event.getX();
y=(int) event.getY();
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
Log.d(TAG, "mode=DRAG"); // write to LogCat
mode1 = DRAG1;
break;
case MotionEvent.ACTION_UP: // first finger lifted
x_cordinate=(int) event.getX();
y_cordinate=(int) event.getY();
Log.e("x_cordinate==",""+x_cordinate+" "+bmdragImage.getHeight());
Log.e("y_cordinate==",""+y_cordinate+" "+bmdragImage.getWidth());
break;
case MotionEvent.ACTION_POINTER_UP: // second finger lifted
mode1 = NONE1;
Log.d(TAG, "mode1=NONE1");
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);
mode1 = ZOOM1;
Log.d(TAG, "mode=ZOOM" );
}
break;
case MotionEvent.ACTION_MOVE:
Log.e("ACTION_MOVE","ACTION_MOVE");
if (mode1 == DRAG1){
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - start.x, event.getY() - start.y); // create the transformation in the matrix of points
}
else if (mode1 == ZOOM1){
// pinch zooming
float newDist = spacing(event);
Log.d(TAG, "newDist=" + newDist);
if (newDist > 5f){
matrix.set(savedMatrix);
scale = newDist / oldDist; // setting the scaling of the image..
matrix.postScale(scale, scale, mid.x, mid.y);
height=(int) (bmdragImage.getHeight()*scale);
width=(int) (bmdragImage.getWidth()*scale);
Log.e("height int===="+scale,""+height);
Log.e("width int====="+scale,""+width);
}
}
break;
}
view.setImageMatrix(matrix); // display the transformation on screen
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);
}
This code is dragging and zooming is working fine. But my problem is getting x coordinate and y coordinate after drag the image.These x and y values are getting wrong. Because where ever i touch the image with in the relative layout, dragging is working.Because of these code in oncreate of image view params. So x and y values are getting wrong.
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT,
RelativeLayout.LayoutParams.FILL_PARENT);
If i change the image layout params to wrap contnet like the bellow,the image dragging is with in that area only. And zooming also not working properly. But my requirement is drag the image total relative layout.And get the x and y coordinates of image view.
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
Suggestions are appreciated..
I am trying to move an ImageView (not rotate). The movement is supposed to be on the edge of a circle. This circle is also an image view.
based on the onTouch, ACTION_MOVE event, I am trying to move it.
Noe the Dilema is that the use may not move the finger in a perfectly circular fashion but I would like to make sure that the image still moves around edge of this circle.
I am currently using the following inside ACTION_MOVE:
mCurrTempIndicator.setTranslationX(event.getX());
mCurrTempIndicator.setTranslationY(event.getY());
But this will not move in a perfect circle.
could someone please help.
UPDATE: code
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mInitialX = event.getX();
mInitialY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
mEndX = event.getX();
mEndY = event.getY();
float deltaX = mEndX - mInitialX;
float deltaY = mEndY - mInitialY;
double angleInDegrees = Math.atan(deltaY / deltaX) * 180 / Math.PI;
mInitialX = mEndX;
mInitialY = mEndY;
mCurrTempIndicator.setRotation((float)angleInDegrees);
mCurrTempIndicator.setTranslationX((float)(310*(Math.cos(angleInDegrees))));
mCurrTempIndicator.setTranslationY((float)(310*(Math.sin(angleInDegrees))));
break;
case MotionEvent.ACTION_UP:
allowRotating = true;
break;
}
return true;
}
calculate the center Point of the Circle
get the current touch point
calculate the angle between center and new touch point
Calculate the point on the circle using angle and radius of circle (x = r * cos(angle), y = r * sin(angle)).
Reset the image position to the new point.
To get the angle use the below equation
deltaY = P2_y - P1_y
deltaX = P2_x - P1_x
angleInDegrees = arctan(deltaY / deltaX) * 180 / PI
//Code inside ACTION_MOVE case
mInitialX = event.getX();
mInitialY = event.getY();
float deltaX = circleCenter.x - mInitialX;
float deltaY = circleCenter.y - mInitialY;
double angleInRadian = Math.atan2(yDiff, xDiff);
PointF pointOnCircle = new PointF();
pointOnCircle.x = circleCenter.x + ((float)(circleRadius*(Math.cos(angleInRadian))));
pointOnCircle.y = circleCenter.y + ((float)(circleRadius*(Math.cos(angleInRadian))));
I have a task to pinch and zoom the imageview, I have made an app where I am swiping the images and it is working fine; now I want to Pinch and Zoom the imageview on the same class ;but I am not able to do this.I have gone through various example but it seems nothing is helping in this case.Below is my code,or provide me some another example for this problem.
imageView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent event) {
bitmap = BitmapFactory.decodeResource(context.getResources(), image_id[position]);
bmpWidth = bitmap.getWidth();
bmpHeight = bitmap.getHeight();
distCurrent = 1;
dist0 = 1;
drawMatrix();
float distx, disty;
switch(event.getAction() & MotionEvent.ACTION_MASK){
case MotionEvent.ACTION_DOWN:
//A pressed gesture has started, the motion contains the initial starting location.
touchState = TOUCH;
break;
case MotionEvent.ACTION_POINTER_UP:
//A non-primary pointer has gone up.
touchState = TOUCH;
break;
case MotionEvent.ACTION_POINTER_DOWN:
//A non-primary pointer has gone down.
touchState = PINCH;
//Get the distance when the second pointer touch
distx = event.getX(0) - event.getX(1);
disty = event.getY(0) - event.getY(1);
dist0 = FloatMath.sqrt(distx * distx + disty * disty);
break;
case MotionEvent.ACTION_MOVE:
//A change has happened during a press gesture (between ACTION_DOWN and ACTION_UP).
if(touchState == PINCH){
//Get the current distance
distx = event.getX(0) - event.getX(1);
disty = event.getY(0) - event.getY(1);
distCurrent = FloatMath.sqrt(distx * distx + disty * disty);
drawMatrix();
}
break;
case MotionEvent.ACTION_UP:
//A pressed gesture has finished.
touchState = IDLE;
break;
}
touchState = IDLE;
return true;
}
});
private void drawMatrix(){
float curScale = distCurrent/dist0;
if (curScale < 0.1){
curScale = 0.1f;
}
Bitmap resizedBitmap;
int newHeight = (int) (bmpHeight * curScale);
int newWidth = (int) (bmpWidth * curScale);
System.out.println("new width: "+newWidth+" new heigt: "+newHeight);
resizedBitmap = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, false);
System.out.println("resized bitmap: "+resizedBitmap);
imageView.setImageBitmap(resizedBitmap);
}
I have to integrate the same functionality into the my application.
But as we know zoomable ImageView is not possible in android.
I have use the following library:
https://github.com/sephiroth74/ImageViewZoom
Try this. May be helps you...:)
We have a longpress detection on a button. When detected, the view should be dismissed (back to the game view) and the object chosen with the button shall be at the coordinates of the longpress. That's the easy part, the hard part is to then change the coordinates with the finger, without releasing it.
Okay so i'm trying to reformulate this: We have two views displayed on top of eachother. What we want is a longclick detected in the top view, to then dismiss the top view, and without releasing the finger, get touchevents in the bottom view.
This is our class gameView: (this code contains a lot of code unneccesay for the problem)
#Override
public boolean onTouchEvent(MotionEvent event) {
gestureDetector.onTouchEvent(event);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mode = DRAG;
//We assign the current X and Y coordinate of the finger to startX and startY minus the previously translated
//amount for each coordinates This works even when we are translating the first time because the initial
//values for these two variables is zero.
startX = event.getX() - previousTranslateX;
startY = event.getY() - previousTranslateY;
break;
case MotionEvent.ACTION_MOVE:
translateX = event.getX() - startX;
translateY = event.getY() - startY;
gestureHandler.setTranslation(translateX, translateY);
//We cannot use startX and startY directly because we have adjusted their values using the previous translation values.
//This is why we need to add those values to startX and startY so that we can get the actual coordinates of the finger.
double distance = Math.sqrt(Math.pow(event.getX() - (startX + previousTranslateX), 2) +
Math.pow(event.getY() - (startY + previousTranslateY), 2)
);
if(distance > 0) {
dragged = true;
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
mode = ZOOM;
scaleToX = event.getX();
scaleToY = event.getY();
break;
case MotionEvent.ACTION_UP:
mode = NONE;
dragged = false;
//All fingers went up, so let's save the value of translateX and translateY into previousTranslateX and
//previousTranslate
previousTranslateX = translateX;
previousTranslateY = translateY;
int x = (int)((-translateX/scaleFactorX)+(event.getX()/this.scaleFactorX));
int y = (int)((-translateY/scaleFactorY)+(event.getY()/this.scaleFactorY));
map.click(getContext(), x, y);
for(CastleTile castleTile : map.getCastleTiles()) {
if(castleTile.getRect().contains((int)((-translateX/scaleFactorX)+(event.getX()/this.scaleFactorX)), (int)((-translateY/scaleFactorY)+(event.getY()/this.scaleFactorY)))){
Log.d("Castle to your service", "Boes");
castleSettings.show();
}
}
break;
case MotionEvent.ACTION_POINTER_UP:
mode = DRAG;
//This is not strictly necessary; we save the value of translateX and translateY into previousTranslateX
//and previousTranslateY when the second finger goes up
previousTranslateX = translateX;
previousTranslateY = translateY;
break;
}
detector.onTouchEvent(event);
//We redraw the canvas only in the following cases:
//
// o The mode is ZOOM
// OR
// o The mode is DRAG and the scale factor is not equal to 1 (meaning we have zoomed) and dragged is
// set to true (meaning the finger has actually moved)
if ((mode == DRAG && scaleFactorX != 1f && scaleFactorY != 1f && dragged) || mode == ZOOM) {
invalidate();
}
return true;
}
#Override
public boolean onLongClick(View v) {
castleSettings.dismiss();
return true;
}
And this is the gestureHandler:
public void onLongPress(MotionEvent event) {
map.longClick(context, (int)((-translateX/scaleFactorX)+(event.getX()/this.scaleFactorX)), (int)((-translateY/scaleFactorY)+(event.getY()/this.scaleFactorY)));
}
Sorry for eventual lack of information or bad explaination :)
How can i determine the direction of gesture ? The use case is shown in the image link. what is the right logic for detecting in which direction the person is trying to move the ball in the circular path ? I have called the direction method in move gesture...Can someone help me fine tune this ... ?
http://www.shrenikvikam.com/wp-content/uploads/2011/04/214e422a43E11S3.png-150x134.png
private String getDirection(float firstTouchX, float finalTouchX){
if((firstTouchX - finalTouchX)>0)
return "Left";
else
return "Right";
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
// MotionEvent class constant signifying a finger-down event
case MotionEvent.ACTION_DOWN: {
Log.d("ACTION DOWN","Value ->");
final float x = event.getX();
final float y = event.getY();
initialTouchX = x;
initialTouchY = y;
break;
}
// MotionEvent class constant signifying a finger-drag event
case MotionEvent.ACTION_MOVE: {
final float x = event.getX();
final float y = event.getY();
final String direction = getDirection(initialTouchX,x);
Log.d("ACTION MOVE","diff in initial and cur value of x ->" + direction + (initialTouchX - x) + initialTouchX + "y->" + initialTouchY);
break;
}
// MotionEvent class constant signifying a finger-up event
case MotionEvent.ACTION_UP: {
Log.d("ACTION UP","Value ->");
break;
}
}
return true;
}
It seems like the slope of the line formed by the two touch points should be equal to the tangent of the circle at that point. This link has most of the math to pursue such a solution
I have used the difference between angles to the center point of the circle with good success. That may be the way to go as well.
If you are trying to determine which way to move the ball around the ciricle, it doesn't make sense for getDirection to return "Left" and "Right", it should be working with "Clockwise" and "Counterclockwise". Consider, for example, when the ball is at the 20 marker in your image: At this point every point on the circle is "Right" of where you are now...
In order to determine if the ball is moving clockwise or counterclockwise you need to consider both the x and y co-ordinates of the touch points, the x co-ordinate alone is not sufficient. You also need to know where the centre of the circle is. I would suggest in order to determine the direction of movement, you calculate the angle between the touch points and the centre of the circle.
prevTouchX = event.getHistoricalX(event.getHistorySize()-1);
currentTouchX = event.getX();
if(currentTouchX<prevTouchX){
Log.d("LEFT",event.getX()+" and "+event.getY());
}
if(currentTouchX>prevTouchX){
Log.d("RIGHT",event.getX()+" and "+event.getY());
}
Similarly for UP/DOWN
I use this code for rotating a view. It works very well. Have a look at this;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
firstX = event.getX();
firstY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
int dx =(int) (event.getX() - firstX);
int dy =(int) (event.getY() - firstY);
Log.d("Distance Rotate Touch",Integer.toString((int) (firstX-dx)));
if (signView.getRotation()<180){
if (firstX - dx > 15 && firstY - dy > 15 ){
View.setRotation(signView.getRotation()-5);
}else if(firstX - dx < -15 && firstY - dy < 15 ){
View.setRotation(signView.getRotation()+5);
}
}else {
if (firstX - dx > 10 && firstY - dy < -10 ){
View.setRotation(signView.getRotation()+5);
}else if(firstX-dx < -10 && firstY - dy < -15 ){
View.setRotation(signView.getRotation()-5);
}
}
break;
default: return true;
}