Android: Detecting gesture swipes AND taps in a view

I have a custom calendar in one of my activities which should respond to swipe gestures to change the current month, but also respond to tap events on dates.

For some odd reason, my view just wasn't responding to the events triggered by the GestureDetector. It would work with either swipe or tap, but not both.

When both "worked", the tap would be triggered by a ACTION_DOWN at the start and end of the swipe. If I got the tap working, it'd break the swipe functionality.

force
Swipe functionality working the way it's supposed to.

However, if I applied the exact same code to the Activity without the view and it'd work just fine. This was annoying =\

The majority of code samples and tutorials online would only deal with detecting and handling swipes in an activity. Any tutorials about swipes in views weren't about swipes and single tap.

Eventually I figured out that the detection code was meant to go into the Activity, not a combination of both.

This code sample goes into Activity.onCreate().

final GestureDetector gestureDetector = new GestureDetector(new GestureListener());

calendar.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(final View view, final MotionEvent event) {
if (gestureDetector.onTouchEvent(event)) {
return false;
}

return true;
}
});

And below is the GestureListener class. I also put this code in the Activity class code, but it can easily be decoupled for cleanliness.

class GestureListener extends SimpleOnGestureListener {
@Override
public boolean onSingleTapConfirmed(MotionEvent event) {
// Trigger the touch event on the calendar
calendar.onTouchEvent(event);
return super.onSingleTapUp(event);
}

@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
ViewConfiguration viewConfiguration = ViewConfiguration.get(EventsActivity.this);
int minSwipeDistance = viewConfiguration.getScaledPagingTouchSlop();
int minSwipeVelocity = viewConfiguration.getScaledMinimumFlingVelocity();
int maxSwipeOffPath = viewConfiguration.getScaledTouchSlop();

if (Math.abs(e1.getY() - e2.getY()) > maxSwipeOffPath) {
return false;
}

if (Math.abs(velocityX) > minSwipeVelocity) {
// Right to left swipe
if (e1.getX() - e2.getX() > minSwipeDistance) {
calendar.nextMonth();
}
// Left to right
else if (e2.getX() - e1.getX() > minSwipeDistance) {
calendar.previousMonth();
}

// Call some app-related functions to update the display
displayDate(calendar.getMonth(), calendar.getYear());
}

return false;
}
}

This code detects left/right swipes, with consideration to scaling of DPI and screen sizes. It also correctly detects single clicks on the calendar.

It also has some "error detection" in terms of maxSwipeOffPath (accidental swipes in the wrong direction) and minSwipeVelocity/minSwipeDistance (too slow or too short) to be consistent with swipe detection on your whole Android device.

Note: I tend to support API level 4 where possible, but getScaledPagingTouchSlop() requires level 8 (Android 2.2).

Sources

 
Copyright © Twig's Tech Tips
Theme by BloggerThemes & TopWPThemes Sponsored by iBlogtoBlog