Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Forward events to the next handler?

Discussion in 'UGUI & TextMesh Pro' started by DonKanallie, Nov 4, 2014.

  1. DonKanallie

    DonKanallie

    Joined:
    Jul 17, 2013
    Posts:
    10
    I played around with the new UI and encountered one problem where I can't find any useful resources online to help me, so I hope somebody here can help me out.

    I want to create an horizontal scrollrect with some items in it (this is easy), then I want to be able to vertically drag items out of the scrollrect, but horizontal movements should still scroll the scrollrect.

    Right now, as soon as my items have a component that implements any of the I*DragHandler interfaces, they receive the pointer events and "consume" them (I.E. the scrollrect doesn't get any pointer events any more and doesn't scroll anymore).

    All I need would be to be able to send the event to the next receiver.

    Maybe I have to explain it better, the iOS and Mac OS X UI frameworks have the concept of a "Responder Chain"; When an event occurs, the first Responder (In Unity that would be any class implementing a handler) receives the event, it can then process the event and/or send the event further down the chain to let others process the event as well.

    I know I can send my buttons a reference to the scrollrect and let them scroll the scrollrect. But I feel that this is extremely ugly, all the scrolling code for these events is already there in the Scrollrect component.

    All I need to do is tell the event system to send the event further as if my buttons hadn't had an handler!

    Is this possible with the Unity event system? I hope I just missed something...
     
    Shahdee and KayelGee like this.
  2. holyjewsus

    holyjewsus

    Joined:
    Mar 7, 2011
    Posts:
    624
    wondering this as well
     
  3. KayelGee

    KayelGee

    Joined:
    Nov 29, 2012
    Posts:
    4
    I would like to know aswell if this is possible out of the box or which components would need to be rewritten by me to make this work. A developer's answer to this would be nice.
     
  4. MalcomCZ

    MalcomCZ

    Joined:
    Sep 26, 2014
    Posts:
    6
    I think that you are looking for ExecuteEvents (http://docs.unity3d.com/460/Documentation/ScriptReference/EventSystems.ExecuteEvents.html)

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.EventSystems;
    3. using UnityEngine.UI;
    4.  
    5. public class SubView : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler {
    6.    
    7.     private ScrollRect sr;
    8.  
    9.     private void Start() {
    10.         sr = transform.parent.GetComponentInParent<ScrollRect>();
    11.     }
    12.  
    13.     public void OnBeginDrag(PointerEventData eventData) {
    14.         ExecuteEvents.beginDragHandler(sr, eventData);      
    15.     }
    16.  
    17.     public void OnDrag(PointerEventData eventData) {
    18.         ExecuteEvents.dragHandler(sr, eventData);
    19.     }
    20.  
    21.     public void OnEndDrag(PointerEventData eventData) {
    22.         ExecuteEvents.endDragHandler(sr, eventData);      
    23.     }
    24. }
     
  5. DonKanallie

    DonKanallie

    Joined:
    Jul 17, 2013
    Posts:
    10
    Thanks MalcomCZ, but `SubView` would still have to know that there is a `ScrollRect` above it to which it should forwards event to, I would like to achieve that without that reference. Just like:

    Code (CSharp):
    1. public void OnBeginDrag(PointerEventData eventData) {
    2.     ExecuteEvents.nextBeginDragHandler(eventData);
    3.     // Pseudo-Code
    4. }
     
  6. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    Vote For This Idea!

    In the meantime I'll offer the following workaround.
    Copy the following into your project:
    Code (CSharp):
    1. public static class GameObjectExtensions
    2. {
    3.     public static ForwardPointerEvent<TEventData> ForwardPointerEvent<TEventData>(this GameObject gameObject, TEventData eventData)
    4.         where TEventData : PointerEventData
    5.     {
    6.         return new ForwardPointerEvent<TEventData>(gameObject, eventData);
    7.     }
    8. }
    9.  
    10. public class ForwardPointerEvent<TData> where TData : PointerEventData
    11. {
    12.     private readonly GameObject _root;
    13.     private readonly TData _data;
    14.  
    15.     public ForwardPointerEvent(GameObject root, TData data)
    16.     {
    17.         _root = root;
    18.         _data = data;
    19.     }
    20.  
    21.     public void To<THandler>(Func<THandler, Action<TData>> selectMethod) where THandler : IEventSystemHandler
    22.     {
    23.         if(_root == null)
    24.         {
    25.             return;
    26.         }
    27.  
    28.         var results = new List<RaycastResult>();
    29.         EventSystem.current.RaycastAll(_data, results);
    30.  
    31.         var foundRoot = false;
    32.         foreach(var result in results)
    33.         {
    34.             if(foundRoot && result.gameObject != null)
    35.             {
    36.                 if(ExecuteEvents.Execute(result.gameObject, _data, new ExecuteEvents.EventFunction<THandler>((h, b) => selectMethod(h)(ExecuteEvents.ValidateEventData<TData>(b)))))
    37.                 {
    38.                     return;
    39.                 }
    40.                    
    41.             }
    42.             else if(result.gameObject == _root)
    43.             {
    44.                 foundRoot = true;
    45.             }
    46.         }
    47.     }
    48. }
    To be used as follows:
    Code (CSharp):
    1. public class ForwardTest : MonoBehaviour, IPointerDownHandler
    2. {
    3.     void IPointerDownHandler.OnPointerDown(PointerEventData eventData)
    4.     {
    5.         Debug.Log("ForwardTest.OnPointerDown");
    6.         gameObject.ForwardPointerEvent(eventData).To<IPointerDownHandler>(h => h.OnPointerDown);
    7.     }
    8. }
    Biggest downside is that every forwarding of the event results in a RaycastAll and iterating through results to find the next valid handler.

    Good coding to y'all!
     
  7. yecpster

    yecpster

    Joined:
    May 25, 2016
    Posts:
    1
    Thanks a lot, it's just what I looking for.
     
  8. IgorAherne

    IgorAherne

    Joined:
    May 15, 2013
    Posts:
    383