Transfer longpress from one android view to another, without releasing finger - android

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 :)

Related

Getting a particular position in canvas after zoom the canvas android

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;
}

Android have user draw a scaling circle

I'm trying to make a basic "Paint"-esque app for a class, and part of what I'm trying to implement is the ability to draw a circle that scales in size as the user moves their finger to pick the center, and drags it outward to the desired radius. The problem is, no matter what I try it just ends up repeatedly stamping a small circle where ever the user moves their finger. The idea is the app will get the coordinates for the center (tX, tY) on the press down, draw a circle with a radius r every time the user moves, then finalize it when they lift their finger.
Edit: the commented out sections are parts where I was testing different things.
Code for my onMotionEvent custom class:
#Override
public boolean onTouchEvent(MotionEvent event) {
//detect user touch
float tX = event.getX();
float tY = event.getY();
float rX = 0;
float rY = 0;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
drawPath.moveTo(tX, tY);
break;
case MotionEvent.ACTION_MOVE:
if(shapes){
rX = (int) event.getX();
rY = (int) event.getY();
r = (float) Math.sqrt(Math.pow(tX - rX, 2) + Math.pow(tY - rY, 2));
drawCanvas.drawCircle(tX, tY, r, drawPaint);
invalidate();
}else{
drawPath.lineTo(tX, tY);
}
break;
case MotionEvent.ACTION_UP:
/*rX = event.getX();
rY = event.getY();
r = (float) Math.sqrt(Math.pow(tX - rX, 2) + Math.pow(tY - rY, 2));*/
if(shapes){
if(shape_sel == 0){
//drawCanvas.drawCircle(tX, tY, r, drawPaint);
drawPath.reset();
/*}else if(shape_sel == 1){
}
else{
*/}
}else{
drawCanvas.drawPath(drawPath, drawPaint);
drawPath.reset();
}
break;
default:
return false;
}
invalidate();
return true;
}
You aren't saving tx and ty on touch down, you're resetting them on every event. You need to save tx and ty in class level variables inside the down case.

Canvas MotionEvent, bitmap does not get dragged as expected

I am using MotionEvent and Matrix to drag my bitmap but instead the bitmap gets "translated" to a nearby region (most of the times in the opposite direction of press). I want to be able to drag it using Matrix translations. Here's my code.
switch(action){
case MotionEvent.ACTION_DOWN: {
final float touchX = event.getX();
final float touchY = event.getY();
//check to see if the user is pressing at most 80 pixels far from the bitmap
if(((Math.abs(touchX - player.prevX)<=80) && ((Math.abs(touchY - player.prevY)<=80)))){
//if so then proceed to drag it to a new location
player.isDraggable = true;
}
break;
}
case MotionEvent.ACTION_MOVE: {
if(player.isDraggable){
player.x = event.getX();
player.y = event.getY();
float dx = player.x - player.prevX, dy = player.y - player.prevY;
player.matrix.postTranslate(dx, dy);
player.prevX = player.x;
player.prevY = player.y;
player.isDraggable = false;
}
break;
}
}
public void draw(Canvas canvas) {
canvas.drawBitmap(background, 0, 0, null);
canvas.drawBitmap(player.bmp, player.matrix, null);
for(int i=0;i<particles.size();i++){
particles.get(i).drawShower(canvas);
}
}
Your onTouch() method should return true to be able to get
continuously values from the MotionEvent.
You set the isDraggable attribute of your player immediately to
false, when an attempt to drag the image appears. After that, you check each time, if it is true, but it wont be. I don't know, what is the logic behind that, but try something else!

how to make left right activity slider?

Any suggestions for how to make an activity slider with "slide left" and "slide right" like a typical image slider??
I tried with: (implements OnTouchListener)
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
{
// code
break;
}
case MotionEvent.ACTION_UP:
{
// code
break;
}
case MotionEvent.ACTION_MOVE:
{
// code
break;
}
}
return true;
}
but don't have LEFT, RIGHT choice.
I don't need use buttons, just I need do somethings like the image slider for ipad2 but with activities for a customer app.
Thanks
You need to calculate by your own for slide left and right movement
MotionEvent.ACTION_UP
A pressed gesture has finished, the motion contains the final release location as well as any intermediate points since the last down or move event.
MotionEvent.ACTION_DOWN
A pressed gesture has started, the motion contains the initial starting location.
Use onTouchEvent(), and calculate difference in X and difference in Y by where the user presses down and lifts up. Use these values to figure out the direction of the move.
float x1, x2, y1, y2;
String direction;
switch(event.getAction()) {
case(MotionEvent.ACTION_DOWN):
x1 = event.getX();
y1 = event.getY();
break;
case(MotionEvent.ACTION_UP) {
x2 = event.getX();
y2 = event.getY();
float differenceInX = x2-x1;
float differenceInY = y2-y1;
// Use dx and dy to determine the direction
if(Math.abs(differenceInX) > Math.abs(differenceInY)) {
if(differenceInX > 0) direction = "right";
else direction = "left";
} else {
if(differenceInY > 0) direction = "down";
else direction = "up";
}
}
}

Touch move gesture logic...how to determine direction of movement in 2d?

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;
}

Categories

Resources