How can I detect a fling gesture when there are wi

2019-06-10 07:14发布

问题:

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>

回答1:

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.

@Override
public boolean dispatchTouchEvent(MotionEvent event) {
    gestureDetector.onTouchEvent(event);
    return super.dispatchTouchEvent(event);
}

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.