As I know, if my onTouch method returns false, after the initial ACTION_DOWN case it does not start tracking the movement, and if I return true, it does. But I have some cases when I need to stop tracking the movement from some moment. How do I achieve this? I tried to returning false when my condition holds, but it continues to run into that case. How to cancel or stop the motion event?
Here is the code I have for my drag and drop application, and when the X is less than 100, I just want to stop dragging. How can I achieve this?
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
imageTouchX = (int) event.getRawX() - (int) img.getX();
imageTouchY = (int) event.getRawY() - (int) img.getY();
break;
case MotionEvent.ACTION_MOVE:
int x_cord = (int) event.getRawX();
int y_cord = (int) event.getRawY();
img.setX(x_cord - imageTouchX);
img.setY(y_cord - imageTouchY);
if(img.getX() < 100){
return false;
}
break;
default:
break;
}
return true;
}
Thanks in advance.
what if the img goes under the x location of 100 and then comes back ?
one way to do it is to disable the touchevent all together, but then how you'll get the next touchevents ? unless it's going to be another view that will receive the touch event, anyhow, if you stop the touch events you won't receive any touch events again, and if this is what you wish to get, just disable the touchevent for this view, you can enable it again when you choose, good luck ! :)
Related
At first i always get the ACTION_DOWN mesage so i googled and i found that i have to return TRUE at the end. So i changed it and i started to get always ACTION_UP. I dont understand why.
linearLayoutDraggable.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
//ConstraintLayout.LayoutParams par = (ConstraintLayout.LayoutParams)v.getLayoutParams();
CardView.LayoutParams par = (CardView.LayoutParams)v.getLayoutParams();
switch (event.getAction()) {
case MotionEvent.ACTION_UP: {
//par.height = 40;
Toast.makeText(MagMainNewActivity.this, "UP", Toast.LENGTH_SHORT).show();
// par.height=300;
// par.topMargin = (int) event.getRawY() - (v.getHeight());
// par.leftMargin = (int) event.getRawX() - (v.getWidth() / 2);
// v.setLayoutParams(par);
break;
} //inner case UP
case MotionEvent.ACTION_DOWN: {
Toast.makeText(MagMainNewActivity.this, "DOWN", Toast.LENGTH_SHORT).show();
// par.height = 115;
// //par.width = 60;
// v.setLayoutParams(par);
break;
} //inner case UP
} //inner switch
return true;
}
});
The onTouchListener receive motion gestures, so (while returning true) if you receive a ACTION_DOWN, you will receive each ACTION_MOVE finalized with only ONE ACTION_UP that means the pointer (finger) was removed from the screen at that point.
A click action is represented from a ACTION_DOWN plus a ACTION_UP, while a ACTION_DOWN without a UP is a long press.
Maybe you are seeing just the UP message from the toast since both events are trigged sequentially and the second toast overrided the first one, if you add Log.v("MMNA", "DOWN") you can check both at the Logcat
Because before finger is up finger down is first, this means MotionEvent.ACTION_DOWN is came frist. It check event action and if finger touch a screen action is MotionEvent.ACTION_DOWN and it break. Sorry for bad English
I'm kind of new, but having a really good time figuring this stuff out. Hope you don't mind helping me where I'm stuck.
Here is my OnTouchListener. It is for the display of a timer and I want the timer to turn off if someone moves the view that displays the time.
I need it so that the view is moved past a certain point and then it implements. Otherwise it gets a little confused with the a click gesture. I'm going to set it so that the timer pauses on click.
The problem is. I'll set the view as "GONE", so that you won't see it after it moves, but I still need the view to go back to it's original place so that when the next timer is started again, it will be reset.
//setOnTouchListener Here
zoneATimerText.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
dX = view.getX() - event.getRawX();
dY = view.getY() - event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
destroyCountDownTimer();
view.animate()
.x(event.getRawX() + dX)
.y(event.getRawY() + dY)
.setDuration(0)
.start();
Log.v("on move", "you're moving");
break;
default:
return true;
}
return true;
}
});
Save the original position of the view i.e x,y at class level, and when your animation is done you hide the view with visibility gone at that time simply reset the position position of the view with method(view.setX(),view.setY()).
I got a view in android which I want to accept onLongPress actions.
I've got a OnTouch method which handles stuff when moving around across the screen. But when long pressing without moving the finger, the OnLongPress method should be called.
My effort so far is that I got the onTouch events working. But now, when swiping around the view, the onLongPress method gets called, because logically, I am long pressing the screen.
I just want the onLongPress work when the finger is held still on the screen without moving, is there a way how to achieve this?
You should cancel the long press. From the documentation:
public void cancelLongPress()
Cancels a pending long press. Your subclass can
use this if you want the context menu to come up if the user presses
and holds at the same place, but you don't want it to come up if they
press and then move around enough to cause scrolling.
How about something like this:
#Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = event.getX();
downTime = Calendar.getInstance().getTimeInMillis();
return true;
case MotionEvent.ACTION_UP:
upX = event.getX();
upTime = Calendar.getInstance().getTimeInMillis();
float deltaX = downX - upX;
float deltaTime = upTime - downTime;
if((deltaX < UNACCEPTABLE_MOVE_DISTANCE) && (deltaTime > MINIMUM_TIME))
//REPORT LONG PRESS WITH INTERFACE
else
//REPORT SOMETHING ELSE
return true;
default:
return true;
}
}
I am using a small square RelativeLayout as a game pad for movement in a neighboring GLSurfaceView.
I set it up so that in the onTouch method of the RelativeLayout's onTouchListenner I call a method built into the GLSurfaceView that updates the translation and rotation coordinates for my drawing.
I have everything working fine, except for the fact that touch events are only triggered if the user moves his or her finger on the RelativeLayout.
I would like it to feel a little bit like a joystick: if you leave your finger pressed on the top of the RelativeLayout, then you will keep going "up" ( or more programatically: the event.getX() and event.getY() that were sent last should get looped, or re-sent, in the GLSurfaceView until the user either moves his finger inside the RelativeLayout, or stops touching the RelativeLayout altogether.)
What should I use to detect whether or not the RelativeLayout is currently being touched (even if there is no motion in the said touch)?
Thanks!
So this is what I came up pretty much simultaneously with csmcklvey
if(event.getAction()==MotionEvent.ACTION_UP)
gM.isTouchedL = false;
else
gM.isTouchedL = true;
return true;
Where .isTouchedL is the "control boolean" I use in the GLSurfaceView
Green lit csmc's answer anyways! :)
I have used rotation animation in one of my apps, which is using the onTouchEven of view. Major function has been performed in event "ACTION_MOVE". It will help you, to get through.
public boolean onTouch(View v, MotionEvent event)
{
final float xc = volumeButton.getWidth() / 2;
final float yc = volumeButton.getHeight() / 2;
final float x = event.getX();
final float y = event.getY();
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
{
// volumeButton.clearAnimation();
// mCurrAngle = Math.toDegrees(Math.atan2(x - xc, yc - y));
break;
}
case MotionEvent.ACTION_MOVE:
{
mPrevAngle = mCurrAngle;
mCurrAngle = Math.toDegrees(Math.atan2(x - xc, yc - y));
animate(mPrevAngle, mCurrAngle, 100);
break;
}
case MotionEvent.ACTION_UP :
{
mPrevAngle = mCurrAngle = 0;
break;
}
}
return true;
}
You might be able to use the event.getAction() method of the MotionEvent parameter of your onTouch() method. You can check to see if it is MotionEvent.ACTION_DOWN or MotionEvent.ACTION_UP.
if (event.getAction() == MotionEvent.ACTION_DOWN) {
//start something
}
else if (event.getAction() == MotionEvent.ACTION_UP) {
//stop something
}
My thought is that you might be able to start or stop a thread in this manner but either way this might at least give you some more information about when the user actually presses and lifts his/her finger.
I was wondering how to get accurate, live get(x) and get(y) values for a MotionEvent? What is happening is that when I touch a specific area on the screen, I tell an action to happen.
The problem is that once I touch the screen and take my finger off, it still thinks my finger is at the same location (since that was the last location I touched). So when I have more than one Down event (for multitouch) it throws everything off. Is there a way to reset the X and Y values so when I let off the screen, they go back to 0 or null (or whatever)? Thanks
What you are describing isn't a problem. You the programmer are responsible for keeping track of the touch locations and what they mean. If you care about motion you need to keep track of the previous touch and the current touch each time a touch occurs. I find something like this works great:
public int x=-1,y=-1,prevX=-1, prevY=-1;
public boolean onTouch(View v, MotionEvent event)
{
prevX = x;
prevY = y;
int x = (int)event.getX();
int y = (int)event.getY();
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
// there is no prev touch
prevX = -1;
prevY = -1;
// touch down code
break;
case MotionEvent.ACTION_MOVE:
// touch move code
break;
case MotionEvent.ACTION_UP:
// touch up code
break;
}
return true;
}
Just catch the MotionEvent.ACTION_UP or ACTION_MOVE event, depending on when the action needs to happen (since you want it live, you should use the ACTION_MOVE event). You should handle setting external variables when ACTION_DOWN occurs, and handle the results on ACTION_MOVE or ACTION_UP.