Question

I have both an onClickListener and an onFling (using GestureDetector).

If I click on the button the onClickListener fires.

If I fling on the body of the screen then onFling fires.

However if I start the fling from the button, then neither fire.

Layout as follows:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:tools="http://schemas.android.com/tools"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
    <Button
            android:id="@+id/myButton"
            android:layout_margin="50dp"
            android:layout_height="100dp"
            android:layout_width="match_parent"
            android:text="Button"/>
</LinearLayout>

And the code looks like:

public class myLayout extends Activity implements GestureDetector.OnGestureListener {
    private GestureDetector gDetector;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.myLayout);

        gDetector = new GestureDetector(getBaseContext(), this);
        findViewById(R.id.myButton).setOnClickListener(button_OnClickListener);
    }

    final View.OnClickListener button_OnClickListener = new View.OnClickListener() {
        public void onClick(final View buttonView) {
            Toast.makeText(getApplicationContext(), "button pressed", Toast.LENGTH_LONG).show();
        }
    };

    @Override
    public boolean onDown(MotionEvent motionEvent) {
        return true;
    }

    @Override
    public void onShowPress(MotionEvent motionEvent) {
    }

    @Override
    public boolean onSingleTapUp(MotionEvent motionEvent) {
        return false;
    }

    @Override
    public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent2, float v, float v2) {
        return false;
    }

    @Override
    public void onLongPress(MotionEvent motionEvent) {
    }

    @Override
    public boolean onFling(MotionEvent start, MotionEvent finish, float v, float v2) {
        if (start.getRawY() < finish.getRawY()) {
            Toast.makeText(getApplicationContext(), "Fling detected", Toast.LENGTH_LONG).show();
        }
        return false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent me) {
        Log.i("Touch", "onTouchEvent");
        return gDetector.onTouchEvent(me);
    }
}

How can I get the onFling to be run first?

I have looked at other posts for this (e.g. onClick blocking onFling) but not found a suitable answer.

Was it helpful?

Solution

You should try using onInterceptTouchEvent() (or, maybe dispatchTouchEvent(), at this point I'm not sure which will suit better) of the Button's parent (or something even higher in hierarchy) to decide whether to route the touch to the button or the gesture detector.

If the MotionEvent's coordinates belong to the Button's rect and ACTION_DOWN is followed by ACTION_UP shortly, it's a click and should be routed to the Button, but if you receive ACTION_MOVE and the movement continues to the extent where you know it's a swipe - it should be handled by gesture detector.

UPD Here's an answer which explains the technique https://stackoverflow.com/a/3834952/375929

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top