Detect swipe on ListView - android

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."

Related

Android: MotionEvent ACTION_UP doesn't trigger after ACTION_CANCEL

I'm making video stories like instagram. So I met a problem with gestures.
The problem is that ACTION_CANCEL handled when I'm doing these moves and ACTION_UP doesn't call if I raise my finger
I'm in 1st page of ViewPager and I swipe left->right fastly (my finger still on screen)
I'm in the middle of ViewPager and I swipe left->right or right->left, but not finishing the swipe and I'm still in the current page and my finger on screen
I'm moving chaosly on screen (my finger still on screen)
So if I raise my finger after ACTION_CANCEL called, my video stay in "PAUSE" state
Finally, question is: How I can handle Action_Up event after Action_Cancel?
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
if (gestureDetector?.onTouchEvent(event) == true) return true
when (event?.actionMasked) {
MotionEvent.ACTION_DOWN -> {
viewModel.videoPause()
}
MotionEvent.ACTION_UP -> {
viewModel.videoResume()
}
MotionEvent.ACTION_CANCEL -> {
// Handles when doing these moves and ACTION_UP doesn't call if I raise my finger
// 1. I'm in 1st page of ViewPager and I swipe left->right fastly (my finger still on screen)
// 2. I'm in the middle of ViewPager and I swipe left->right or right->left, but not finishing the swipe
// and I'm still in the current page and my finger on screen
// 3. I'm moving chaosly on screen (my finger still on screen)
// So if I raise my finger after ACTION_CANCEL called, my video stay in "PAUSE" state
}
else -> { }
}
return true
}
You don't get an ACTION_UP after an ACTION_CANCEL:
ACTION_CANCEL
public static final int ACTION_CANCEL
Constant for getActionMasked(): The current gesture has been aborted. You will not receive any more points in it. You should treat this as an up event, but not perform any action that you normally would.
Actually there is a way to do this.
#Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
performClick();
switch (event.getAction()){
case MotionEvent.ACTION_MOVE:
float x = event.getX();
float y = event.getY();
Log.d("coordinates: ","x : "+String.valueOf(x)+"y : " + String.valueOf(y));
break;
case MotionEvent.ACTION_UP:
Log.d("action","up")
}
return true;
}
Add this to your parent View. This will show you the location of your finger whenever it moves. And (I don't know how) but when you hold your finger, it also triggers the action up. So whenever the action up is triggered, you'll know that the user held his finger, or whenever the x or y coordinates are outside of your parent view, you can treat it as if the user held his finger. (I got this idea from a canvas question [https://stackoverflow.com/questions/21846584/android-canvas-draw-by-finger])

Looking for a listener that differentiates between up and down events

I apologise for the somewhat noobish question.
I've tried googling it, searching this site and the android developer site, yet didn't manage to find an answer.
I'm looking for a listener that differentiates between up and down events. Currently I'm using OnTouchListener, but it gets triggered very fast, causing a noticable lag, even when I immediately return after an event that is not Down and Up.
I've also tried OnClickListener, but it seems to only get triggered when you lift your finger up, rather than have seperate events for down click and up click like I need.
Would appreciate some help,
Thanks!
YourBtn.setOnTouchListener(new View.OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent event){
if(event.getAction() == MotionEvent.ACTION_UP){
//do stuff
}
else if(event.getAction() == MotionEvent.ACTION_DOWN){
//do stuff
}
else if(event.getAction() == MotionEvent.ACTION_CANCEL){
//do stuff
}
return true; //return false can be used it depends
}
});
P.S: it can be: a button, a textview, an imageview or any UI element
I strongly recommend to always add ACTION_CANCEL to avoid any misbehaviours or crashes
See this:
https://developer.android.com/training/graphics/opengl/touch.html
Override the following method on your activity, then you can treat each case, when the user touch the screen, and when he take of his finger.
#Override
public boolean onTouchEvent(MotionEvent e) {
// MotionEvent reports input details from the touch screen
// and other input controls. In this case, you are only
// interested in events where the touch position changed.
float x = e.getX();
float y = e.getY();
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
// do your stuff
break;
case MotionEvent.ACTION_UP:
// do your stuff
break;
}
return true;
}
You should look at GestureDetector to simplify your touch event handling.

MotionEvent.ACTION_DOWN in Android is too sensitive. This event is received even if the screen is simply touched for a moment

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

Interesting android touch issue

The problem that i am having is I am using a touch listener for the onTouch event it seems that the touch is being called more than once when i just touch it once.
The following is my code
final TextView tv = (TextView)findViewById(R.id.TextView01);
tv.setOnTouchListener(new View.OnTouchListener() {
int count1 =0;
int count2=0;
public boolean onTouch(View arg0, MotionEvent event) {
Log.d("Code777","Touch is being called finger");
int i = event.getPointerCount();
if(i==1 )
{
if(count1==0)
{
Log.d("Code777","Touched with 1 finger");
count1++;
count2=0;
}
}
if (i==2 )
{
if(count2==0)
{
Log.d("Code777","Touched with 2 fingers");
edit.append(tv.getText());
count2++;
count1=0;
}
}
return true;
}
});
Am i doing something wrong ??
It prints the log more than 3-4 times for both single touch and double touch
The problem updated problem is that both the events are getting fired now
if(event.getAction() == MotionEvent.ACTION_POINTER_2_DOWN)
{
Log.d("Code777","2 finger touch");
return true;
}else if(event.getAction() == MotionEvent.ACTION_DOWN)
{
Log.d("Code777","Touched with 1 finger");
return true;
}
You're code will execute during every touch event. The first time it activates, it's likely do to an ACITON_DOWN event (when the user first touches the screen). The second time, it is likely do to an ACTION_UP event (when the user lifts the finger from the screen). Likewise, if you were to swipe your finger around the screen, the same code will execute many times for an ACTION_MOVE event. You have to check for the types of touches that it is. Do something like this:
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
// Do something that should only happen when the user first touches the screen
break;
case MotionEvent.ACTION_MOVE:
// Do something that should only happen when the user is touching the screen
break;
case MotionEvent.ACTION_UP:
// Do something that should only happen when the user stops touching the screen
break;
}
EDIT:
Multitouch in Android is odd at best. Not all devices can handle it. Not all device can handle more than x number of touches, etc. If you want to handle DOWN cases for individual fingers, then you can use the ACTION_POINTER_X items. If you were to have this series of events like so:
1. User touches screen
2. User touches screen with second finger
3. User lifts finger 1
4. User touches screen with finger 1
5. User lifts finger 2
6. User touches screen with finger 2
7. User lifts both finger 1 and finger 2
8. User touches screen with only finger 2
9. User touches screen with finger 1
The events that will be fired will be like this:
1. ACTION_DOWN
2. ACTION_POINTER_2_DOWN
3. ACTION_POINTER_1_UP
4. ACTION_POINTER_1_DOWN
5. ACTION_POINTER_2_UP
6. ACTION_POINTER_2_DOWN
7. ACTION_UP (also, one of the pointers actions will fire depending on which finger was lifted first)
8. ACTION_DOWN
9. ACTION_POINTER_2_DOWN
And so on.
An onTouchListener sends you multiple actions via MotionEvents. You can get the action for the current event with MotionEvent.getAction().
What you notice here is most likely that you get one ACTION_DOWN (a finger has been placed on the display) event followed by some small ACTION_MOVE events when you move the finger(s) slightly. In the end you will get ACTION_UP (a finger has been lifted) You can filter these out by ignoring events with the wrong action.
For example just return from onTouch() when a move event occured.
public boolean onTouch(View arg0, MotionEvent event) {
Log.d("Code777","Touch is being called finger");
if(event.getAction() == MotionEvent.ACTION_MOVE) {
Log.d("Code777", "Move event detected, ignored!");
return false;
}
// Further processing ..
}
or use a switch to differentiate between all relevant events.
See the MotionEvent class documentation for a list of possible actions.
.

"Live" get(x) and get(Y) values (for MotionEvents) ****UPDATE****

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.

Categories

Resources