Background: I'm trying to detect edge swipes in my app (to bring up a menu), and searching stackoverflow seems to indicate that the way to detect swipes is to start with fling detection.
I'm trying to detect a fling event in my app. I can override dispatchTouchEvent()
or onTouchEvent()
and pass the event to a gesture listener and everything works as you would expect.
However, my app has button widgets in it and I can't both detect the fling and use the widgets.
If I call the gesture detector from onTouchEvent()
, flings are not detected if the gesture starts over a widget that consumes the event. If I call the gesture detector from dispatchTouchEvent()
, the widgets don't get the events they need.
I've also tried attaching to the container's onTouchEvent()
but the result was the same.
Finally, I've looked at the source code to ViewPager to see how they do it, and what they do is override onInterceptTouchEvent()
. I can see how and why this works, but I was hoping there was a simpler solution that didn't require me to implement my own container widget.
Source code:
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
public class Fling extends Activity {
private static final String TAG = "FlingTest";
protected GestureDetector gestureDetector;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
gestureDetector = new GestureDetector(this, listener);
}
/*
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (gestureDetector.onTouchEvent(event))
return true;
return super.dispatchTouchEvent(event);
}
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
private final SimpleOnGestureListener listener =
new SimpleOnGestureListener() {
public boolean onDown(MotionEvent e1) { return true; }
public boolean onFling(MotionEvent e1, MotionEvent e2, float vx, float vy) {
Log.d(TAG, "Fling: " + vx + "," + vy);
return true;
}
};
}
The layout.xml file, although pretty much any layout will show these issues:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/buttonPane"
android:background="#446"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<Button
android:text="btn"
android:layout_width="wrap_content" android:layout_height="wrap_content"
/>
<Button
android:text="btn"
android:layout_width="wrap_content" android:layout_height="wrap_content"
/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<Button
android:text="btn"
android:layout_width="wrap_content" android:layout_height="wrap_content"
/>
<Button
android:text="btn"
android:layout_width="wrap_content" android:layout_height="wrap_content"
/>
</LinearLayout>
</LinearLayout>
I've found one answer that seems to work. I change dispatchTouchEvent() to both call the gesture detector and pass the event up the chain.
It's not pretty, and I'm not sure it's robust, but it seems to work.
Still hoping for a better answer, but I think I'll give this method a try.