Search Unity

Resolved Listen from unselected objects for UI events with the Event System

Discussion in 'UGUI & TextMesh Pro' started by devrandomzero, Jun 8, 2023.

  1. devrandomzero

    devrandomzero

    Joined:
    Aug 2, 2020
    Posts:
    43
    Hi,
    with the UI Event System (https://docs.unity3d.com/Packages/com.unity.ugui@1.0/manual/SupportedEvents.html), is there a way from unselected objects to listen globally for events?

    For example I've created a simple main menu with four gameobjects where each one has attached a Selectable component, can I implement the IMoveHandler interface in another UI gameobject to listen for every navigation event done in the main menu?

    I'm asking because at the moment I can trigger a callback only if I implement it on one of the buttons inside the main menu and then if I navigate away from it in playmode.

    I'm asking here before reinventing the wheel making some kind of auxiliary custom event system.

    Thank you as always

    Bye
     
  2. devrandomzero

    devrandomzero

    Joined:
    Aug 2, 2020
    Posts:
    43
    Or maybe if it's possibile to propagate the events up in the hierarchy so I can listen for them in a main menu controller script, that would be equally useful.

    Thank you

    Bye
     
  3. karliss_coldwild

    karliss_coldwild

    Joined:
    Oct 1, 2020
    Posts:
    600
    The approach I currently use is attaching a component to the selectables which forwards the event to nearest parent capable of handling it using the functions of UnityEngine.EventSystems. Unity use this method mostly to find the correct receiver of mouse related events (since the object hit by raycast can be child element of object listening to click events).

    It's not ideal as you potentially have to attach the forwarder to each button in a window. But in certain situations it can still be more convenient than having each button reference the parent window directly or having the window register handler to each object within it.

    Something like this:
    WARNING! I slightly simplified the code removing parts which where specific to my needs so there might be minor mistakes introduced during the process of simplification.
    Code (CSharp):
    1.     public static class EventBubbling
    2.     {
    3.         public static void ForwardToParent<T>(GameObject obj, BaseEventData data, ExecuteEvents.EventFunction<T> functor)
    4.             where T : IEventSystemHandler
    5.         {
    6.             if (obj == null || obj.transform.parent == null)
    7.             {
    8.                 return;
    9.             }
    10.             var parent = obj.transform.parent.gameObject;
    11.             var receiver = ExecuteEvents.GetEventHandler<T>(parent);
    12.             if (receiver == null)
    13.             {
    14.                 return;
    15.             }
    16.             ExecuteEvents.Execute<T>(receiver, data, functor);
    17.         }
    18.     }
    19.  
    20. public class YourCancelForwarder : MonoBehavior, ICancelHandler
    21. {
    22.     public void OnCancel(BaseEventData eventData)
    23.     {
    24.         EventBubbling.ForwardToParent<ICancelHandler>(gameObject, eventData, ExecuteEvents.cancelHandler);
    25.     }
    26. }
    It doesn't have to be single component for event type, you can create an event handler which forwards multiple types of events based on your needs or only forwarding under certain conditions.

    When a game object receives an event, it will be received by all the components of that object implementing corresponding interface. So keep this in mind to avoid having duplicate reaction to an event.
     
  4. devrandomzero

    devrandomzero

    Joined:
    Aug 2, 2020
    Posts:
    43
    Thank you karliss_coldwild for your answer.

    Ok I think I got it, but in this case it's only working for the first direct parent, right?
    If I want to propagate the event to, for example, a grand-grand-parent?

    Yeah but in my specific case I think it's not a problem

    Thank you again for the help

    Bye
     
  5. karliss_coldwild

    karliss_coldwild

    Joined:
    Oct 1, 2020
    Posts:
    600
    No, GetEventHandler returns first ancestor which implements the corresponding event handler. It can be grand-grand-parent or whatever levels up the hierarchy chain, doesn't have to be direct parent. The call to transform.parent in the function above is only to skip the object forwarding the event as it also contains an event handler and would prevent GetEventHandler from searching further.
     
  6. devrandomzero

    devrandomzero

    Joined:
    Aug 2, 2020
    Posts:
    43
    I see, thank you again!