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.
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().
01.
final
GestureDetector gestureDetector =
new
GestureDetector(
new
GestureListener());
02.
03.
calendar.setOnTouchListener(
new
OnTouchListener() {
04.
@Override
05.
public
boolean
onTouch(
final
View view,
final
MotionEvent event) {
06.
if
(gestureDetector.onTouchEvent(event)) {
07.
return
false
;
08.
}
09.
10.
return
true
;
11.
}
12.
});
And below is the GestureListener class. I also put this code in the Activity class code, but it can easily be decoupled for cleanliness.
01.
class
GestureListener
extends
SimpleOnGestureListener {
02.
@Override
03.
public
boolean
onSingleTapConfirmed(MotionEvent event) {
04.
// Trigger the touch event on the calendar
05.
calendar.onTouchEvent(event);
06.
return
super
.onSingleTapUp(event);
07.
}
08.
09.
@Override
10.
public
boolean
onFling(MotionEvent e1, MotionEvent e2,
float
velocityX,
float
velocityY) {
11.
ViewConfiguration viewConfiguration = ViewConfiguration.get(EventsActivity.
this
);
12.
int
minSwipeDistance = viewConfiguration.getScaledPagingTouchSlop();
13.
int
minSwipeVelocity = viewConfiguration.getScaledMinimumFlingVelocity();
14.
int
maxSwipeOffPath = viewConfiguration.getScaledTouchSlop();
15.
16.
if
(Math.abs(e1.getY() - e2.getY()) > maxSwipeOffPath) {
17.
return
false
;
18.
}
19.
20.
if
(Math.abs(velocityX) > minSwipeVelocity) {
21.
// Right to left swipe
22.
if
(e1.getX() - e2.getX() > minSwipeDistance) {
23.
calendar.nextMonth();
24.
}
25.
// Left to right
26.
else
if
(e2.getX() - e1.getX() > minSwipeDistance) {
27.
calendar.previousMonth();
28.
}
29.
30.
// Call some app-related functions to update the display
31.
displayDate(calendar.getMonth(), calendar.getYear());
32.
}
33.
34.
return
false
;
35.
}
36.
}
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).