0
\$\begingroup\$

I've been struggling with this for hours now and have read posts, docs and libgdx sources to better understand what's happening, but I still can't make any sense of this.

I want to accomplish something very simple: stopping a tap on an Actor from propagating through the stage.

The setup is as follows:

  • GameStage defines a gesture listener (for map panning and propagating taps in the map to the Player actor so it can move around)
  • Player has a child actor which can receive clicks

It is on that last child actor that I want to detect clicks, but then not have them propagate to any other actors or be handled by the stage. I define the click handler as follows:

// in child actor:
addListener(new ClickListener() {
   void clicked(...)
});

Nothing surprising here.

The problem is: since the actor is physically located outside the Player parent actor, any clicks on it get picked up by the stage's map gesture handler which then propagates these taps back to the player which makes it move around. I don't want that; this click listener is supposed to handle and swallow the event.

However, none of the following calls I make inside clicked actually cancel the event:

event.handle()
event.stop()
event.cancel()

The only way I could make the event stop from propagating is to use Stage#cancelTouchFocus. However, this has the side effect of dispatching a touchUp event on the stage (why?), which ends up in my gesture listener and gets interpreted as a longPress! Probably because it is paired up with the wrong touchDown...

What am I missing? It can't be that complicated to stop an event from propagating given all the supposed options?

UPDATE: I believe the problem lies in Stage: https://github.com/libgdx/libgdx/blob/2bd1557bc293cb8c2348374771aad832befbe26f/gdx/src/com/badlogic/gdx/scenes/scene2d/Stage.java#L348

It walks over all the listeners that have touch focus, and let's them handle the event. However, it does not break out of the loop as soon as a listener has handled it, thus propagating it further. Is that just a bug?

\$\endgroup\$
  • \$\begingroup\$ That was indeed the problem. When manually testing for isHandled in every gesture callback I get, I can prevent additional logic from firing. That sounds wrong to me though, why wouldn't the event system check that for you? \$\endgroup\$ – Matthias Aug 23 '15 at 10:26
1
\$\begingroup\$

I had the same problem with a window (scene2d.ui.Window). It would propagate click and other events though it shouldn't. I solved it by doing this:

window.addListener(new ActorGestureListener());

As simple as that. Not sure if this is the correct way to do it or if it has some undesirable side effects, but it worked in my case.

\$\endgroup\$
0
\$\begingroup\$

So, it turns out that this is not possible out of the box. The reason it works the way it does is apparently because the touchUp event is not a self-contained event, but is a follow up to touchDown. So in order to cancel them, one has to handle the touchDown in the first place.

Since most event handlers return void (thus cannot signal to their callers that the event has been handled) the only thing one can do is in the gesture handler, check manually if an event was handled by an actor and only propagate it if not, or write your own gesture handler (i.e. not use ActorGestureListener).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.