cancel
Showing results for 
Search instead for 
Did you mean: 

Event dispatching/bubbling and event interception

FayS
Associate II

Hello, I am trying to understand how and in which order exactly events are dispatched to drawables in the draw tree. I was not able to find any information regarding this topic on the touchgfx documentation website. I have two use cases for which this would be relevant:

1. I have a scroll list of custom containers which contain several clickable items. Drag events on the scroll list are intercepted by the touch areas of the clickable items. This makes the scroll list difficult to scroll as you have to hit the tiny spaces in between the clickables for the drag event to register.

clickable-items-in-scroll-listsvg.jpg

I saw two posts on this forum regarding a similar problem:

The accepted answers in both of them did not fix my problem as my application does not allow me to override the touch handling on the view level. The answer given by @GMeur in thread 2 was closer to what i was looking for but only works for me when the scroll list template object itself is clickable. In my case only the children of the template object are clickable. As I do not understand when, how and why touch events are propagated from one drawable to its children/parents, I was not able to solve this problem generically (without having to manually wire a ton of touch event callbacks manually for every widget with which I have this issue).

2. I have a horizontally scrolling scroll list which contains a container template with a vertically scrolling scrollable container. I want to be able to swipe the horizontal scroll list even when hitting the touch area of the scrollable container.

nested-scroll-list-and-scroll-container.jpg

This is possible when using two nested scrollable containers but not with scroll list + scroll containers.

  • Where in the event dispatching chain is the event lost/intercepted when using a scroll list?
  • How does the scrollable container implement its touch event handling for it to intercept the touch events regardless of the content of the scrollable container (such as other clickable items like buttons).

Can anybody explain to me how the event dispatching process works exactly and/or give me a hint how I could solve these two problems generically? Thanks in advance 🙂

1 ACCEPTED SOLUTION

Accepted Solutions
FayS
Associate II

I didn't get why ScrollableContainer behaved differently than all the other containers but I think I found the answer now. For anyone else wondering the same thing here are my findings concerning touch event handling and the scrollable container. Please feel free to correct me if you see something wrong with this answer.

Touch event handling logic

By default touch events are passed only to the first touchable drawable closest to the screen and the screen/view itself. This is why it is possible to change some of the touch event handling by overriding the click, drag and gesture handlers in the view and passing the touch event manually to the desired drawable. This is the method used in the selected answers of the two linked forum threads.

Event bubbling

Another way to do this more generically is to wrap touchable drawables in a mixin class which override the click, drag and gesture event handlers of the drawable and pass them up to a chosen drawable/container or simply to their own parent drawable/container. This way "event bubbling" can be implemented. This is the method shown by @GMeur in thread 2.

Why ScrollableContainer behaves differently

The touch event dispatching logic seems to use the getLastChild method to determine which drawable should handle a touch event. The scrollable container overrides this method to virtually insert itself as the last child in order to intercept the touch events which would otherwise be handled by the actual last child inside a container. Snippet from the source code of ScrollableContainer:

virtual void getLastChild(int16_t x, int16_t y, Drawable** last)
{
    if (isVisible())
    {
        if (isTouchable())
        {
            *last = this;   // if the scrollable container is touchable this causes 
                            // touch events to be intercepted and handled by the click, 
                            // drag, and gesture handlers of ScrollableContainer
        }
        else
        {
            Container::getLastChild(x, y, last);
        }
    }
}

All touch events in the area of the scrollable containers are filtered through this and conditionally passed to its children. Drag events for example are only forwarded to children if the scrollable container cannot scroll in the desired direction. This is why it is possible to nest scrollable containers in an x/y-configuration.

View solution in original post

5 REPLIES 5

Hello @FayS ,

The events are propagated to the widget closest to the screen, which would be the leaf in the drawable tree. 
To be honest, there is no specific way of dealing with touch events when you have multiple different widgets that need to react in a certain ways to the touch. So, it would be nice to try to design the UI in a way that prevents this issue. However, one solution would be to place a transparent box over your containers and then read the touch from that box to decide if it is a click or a drag, and then propagate that to the required widget.

This method can also be used for your second use case to determine if it was a horizontal or vertical drag.
You can set the box to Touchable to receive and handle the touch. 

I hope this helps you 

Mohammad MORADI
ST Software Developer | TouchGFX
FayS
Associate II

Hello @Mohammad MORADI ESFAHANIASL ,

Thanks for your reply. Using an invisible box to intercept touch events seems like a workable solution but causes extra manual work for every widget with which I have this problem. I want to avoid hard coding these interactions because changing requirements for the project might make this approach harder to maintain. I would prefer solving this by creating a mixin or child class for these widgets which handle these cases generically. 

Could you go into more detail about the logic behind the touch event dispatching and why the scroll list and the scroll container behave differently concerning the touch event propagation?

Thanks

Hello @FayS ,

Yes, you can create subclasses or modify the current widgets based on your needs. You can read about the process here .

The difference between the Scroll List and the Scrollable Container is that the Scrollable Container is designed to handle a variety of widgets, while a Scroll List deals only with a specific type. Hence, for the Scrollable Container, the container receives the touch event first and propagates it to the element beneath it. That's why you can click on a button, not release your click, and start a drag in a Scrollable Container. However, such an action is not possible in a Scroll List because the touch event is directed toward the element first.

You can read about the Touch Controller here .

 

Mohammad MORADI
ST Software Developer | TouchGFX
FayS
Associate II

I didn't get why ScrollableContainer behaved differently than all the other containers but I think I found the answer now. For anyone else wondering the same thing here are my findings concerning touch event handling and the scrollable container. Please feel free to correct me if you see something wrong with this answer.

Touch event handling logic

By default touch events are passed only to the first touchable drawable closest to the screen and the screen/view itself. This is why it is possible to change some of the touch event handling by overriding the click, drag and gesture handlers in the view and passing the touch event manually to the desired drawable. This is the method used in the selected answers of the two linked forum threads.

Event bubbling

Another way to do this more generically is to wrap touchable drawables in a mixin class which override the click, drag and gesture event handlers of the drawable and pass them up to a chosen drawable/container or simply to their own parent drawable/container. This way "event bubbling" can be implemented. This is the method shown by @GMeur in thread 2.

Why ScrollableContainer behaves differently

The touch event dispatching logic seems to use the getLastChild method to determine which drawable should handle a touch event. The scrollable container overrides this method to virtually insert itself as the last child in order to intercept the touch events which would otherwise be handled by the actual last child inside a container. Snippet from the source code of ScrollableContainer:

virtual void getLastChild(int16_t x, int16_t y, Drawable** last)
{
    if (isVisible())
    {
        if (isTouchable())
        {
            *last = this;   // if the scrollable container is touchable this causes 
                            // touch events to be intercepted and handled by the click, 
                            // drag, and gesture handlers of ScrollableContainer
        }
        else
        {
            Container::getLastChild(x, y, last);
        }
    }
}

All touch events in the area of the scrollable containers are filtered through this and conditionally passed to its children. Drag events for example are only forwarded to children if the scrollable container cannot scroll in the desired direction. This is why it is possible to nest scrollable containers in an x/y-configuration.

That's a pretty good wrap-up of the answers
Please select it as the accepted solution if you feel comfortable about it.

Best regards,

Mohammad MORADI
ST Software Developer | TouchGFX