kennethc
kennethc

Reputation: 844

How to accept onSingleTapUp() on inner view while accept onFling() on outer view?

I have a view that covers entire screen (let's say ParentView), and child inner view ChildView that covers only portion of it. I want to make ChildView to respond to onSingleTapUp(), while the ParentView respond to onFling(). I am trying to do so by attaching one SimpleOnGestureListener on ChildView and one SimpleOnGestureListener on ParentView.

To accept onSingleTapUp() from ChildView, its listener's onDown() has to return true. But once I do that, the listener tied to ParentView does not hear any motion events anymore since it is taken by the ChildView's listener. Even though ChildView's onFling() returns false, the events do not flow to the ParentView's listener.

How can I make the parent view's listener catch the fling gesture while child view's listener catch tap gesture?

I don't think any source code is needed to explain the situation, but here is a snippet that sets up my ChildView listener.

ChildView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        return singleTapGestureDetector.onTouchEvent(motionEvent);
    }
});

One workaround could be to have both ParentView and ChildView's listeners to handle onFling() while only ChildView's listener handle onSingleTapUp(), but in that case, fling won't be able to happen across the ChildView (like start outside the child and then end within the child), I believe.

Upvotes: 5

Views: 2577

Answers (1)

kennethc
kennethc

Reputation: 844

I don't like my solution, but I found a way to do this. Hopefully somebody else will post better answer in the future, or at least my workaround is useful to somebody otherwise.

As I described in the question, the problem lies on how gesture listener works. For child view to catch onSingleTapUp() event, you return true on onDown(). But once you do that, the subsequent series of events won't go to the parent view even after your child view's onTouch() declares it is no longer interested in the event. If you forcefully call the parent's onTouch() within the child's onTouch() when its gesture detector returns false, yes the parent's onFling() will be invoked but the first MouseEvent argument will be NULL since it was consumed by the child view's onTouch().

I must be missing something since this seems very basic gesture detection scenario. Anyway, I couldn't find a way to do this in reasonable way.

So, my workaround is to make TouchListenerService as a singleton.

Both child view and parent view have this line:

view.setOnTouchListener(TouchListenerService.Instance());

and TouchListenerService starts like this:

public class TouchListenerService
    extends GestureDetector.SimpleOnGestureListener
    implements View.OnTouchListener {

    // some code to implement singleton

    public SingleTapUpHandler SingleTapUpHandler;
    public FlingHandler FlingHandler;

    private View _touchingView;

    GestureDetector gestureDetector;

    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        if (gestureDetector == null)
            gestureDetector =  new GestureDetector(_touchListenerService);

        _touchingView = view;
        boolean result = gestureDetector.onTouchEvent(motionEvent);
        _touchingView = null;
        return result;
    }
    // and some more code

Since it is the same event handler, parent view catches onFling() event successfully while child view can set SingleTapUpHandler to process click event.

Upvotes: 2

Related Questions