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.
Related
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 ! :)
I have a layout(A table layout). Whenever the user performs a "down" gesture, a specific function needs to be called. However,the ontouchlistener captures the event immediately instead of waiting until the user performs a proper "pull down" gesture.
My code is :
homePageTableLayout.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View view, MotionEvent event) {
if ((event.getAction() == MotionEvent.ACTION_DOWN)) {
startSyncData();
}
return true;
}
});
Currently, what's happening is that the startSyncData() function gets called immediately.
The end result should be somewhat similar to the commonly used "pulltorefresh" library for android but in this usecase, I don't have to update the view. I just have to post some data to the server.
I can't use the "pulltorefresh" library because it does not support "pulling" a tablelayout. I tried putting the tablelayout inside a scrollview but that only spoiled the UI.
You can try doing it in ACTION_MOVE or ACTION_UP - if you need it to be done exclusively on swipe down gesture, this should help, introduce four global floats: x, y, x1, y1, then in ACTION_DOWN:
x = event.getX();
y = event.getY();
ACTION_MOVE or ACTION_UP:
x1 = event.getX();
y1 = event.getY();
and then in ACTION_UP:
if (y1 > y) { //pointer moved down (y = 0 is at the top of the screen)
startSyncData();
}
Its not that easy. It works properly since you are catching MotionEvent.ACTION_DOWN. It doesn't mean a gesture like swipe down it means that user touched the screen (finger down, the touch or gesture just started). Now you need to catch MotionEvent.ACTION_UP (finger up, gesture or touch ends here) and decide if there was a gesture you need. http://developer.android.com/training/gestures/detector.html
http://developer.android.com/training/gestures/index.html
MotionEvent.ACTION_MOVE repeatedly gets called. So if you want startSyncData() to run after moving a certain distance, calculate how much you want the user to move before running the method.
The key is that ACTION_DOWN is not a downwards movement on the screen, but it means the user pressed down onto the screen.
homePageTableLayout.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View view, MotionEvent event) {
if ((event.getAction() == MotionEvent.ACTION_DOWN)) {
startFlg = 1;
} else if ((event.getAction() == MotionEvent.ACTION_MOVE)) {
if (startFlg==1){
// Calculate distance moved by using event.getRawX() and event.getRawX() and THEN run your method
startSyncData();
}
}
return true;
}
});
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;
}
}
How do i detect swipe up and down on a listView. I have tried the following methods
Using onSimpleGestureListener,onFling() works for fling( i.e when i leave the screen after swipe). But it doesnt get called on swipe( finger not lifted from screen finally).
2.In onScroll() of onSimpleGestureListener, distanceY is not helpful for detecting up and down swipe. It works fine for fling detection, but fluctuates its values from negative to positive in a particular swipe.
Using onTouchListener
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
before = event.getY();
break;
case MotionEvent.ACTION_MOVE:
now = event.getY();
if (now < before) {
upSwipe()
} else if (now > before) {
downSwipe();
}
}
return false;
}
When i swipe up, variable now sometimes becomes greater than variable previous and sometimes small. So both upSwipe() and downSwipe() is called.
I am banging my head for hours. Not able to sole this.
Have you tried to return true instead of returning false.
Based on the Detecting Common Gestures documentation.
"Beware of creating a listener that returns false for the ACTION_DOWN event. If you do this, the listener will not be called for the subsequent ACTION_MOVE and ACTION_UP string of events. This is because ACTION_DOWN is the starting point for all touch events."
I have an Android applciation which I want it to draw circles around
I used OnTouchListener.
The problem is, when the users "holds" the circle in place, it doesn't update the action.
How can I know if the user's finger is on,when he doesn't move it, with the OnTouchListener
You'll have to check if what kind of event is triggering onTouchEvent.
#Override
public boolean onTouchEvent(MotionEvent event) {
float eventX = event.getX();
float eventY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//Do Nothing
return true;
case MotionEvent.ACTION_MOVE:
//Do Something
path.lineTo(eventX, eventY);
break;
case MotionEvent.ACTION_UP:
//Do Nothing
break;
default:
return false;
}
// Schedules a repaint.
invalidate();
return true;
}
More Information about MotionEvents can be found here.
You can know that by using
MotionEvents:
Reed more here: MotionEvents
ACTION_DOWN is for the first finger that touches the screen. This starts the gesture. The pointer data for this finger is always at index 0 in the MotionEvent.
ACTION_POINTER_DOWN is for extra fingers that enter the screen beyond the first. The pointer data for this finger is at the index returned by getActionIndex().
ACTION_POINTER_UP is sent when a finger leaves the screen but at least one finger is still touching it. The last data sample about the finger that went up is at the index returned by getActionIndex().
ACTION_UP is sent when the last finger leaves the screen. The last data sample about the finger that went up is at index 0. This ends the gesture.
ACTION_CANCEL means the entire gesture was aborted for some reason. This ends the gesture.
here is a good answer to read StackOverFlow
Filter touches by what kind they are:
boolean onScreen = false;
#Override
public boolean onTouchEvent(MotionEvent event) {
float eventX = event.getX(); //X coord of the touch
float eventY = event.getY(); //Y coord of the touch
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// User has touched the screen
onScreen = true;
return true;
case MotionEvent.ACTION_MOVE:
// Finger is being dragged on the screen
onScreen = true; //Not required, just for clarity purposes.
break;
case MotionEvent.ACTION_UP:
// User has lifter finger
onScreen = false;
break;
default:
return false;
}
if(onScreen) {
//Finger is on the screen
}
return true;
}