child objects blocking scrollrect from scrolling

2021 and we still have to do this, thanks for the script. There is no reason for a content item to block scrolling or drag events in a ScrollRect. Unity fix this, or at least add an option in ScrollRect that we can toggle to have this behavior.

5 Likes

I have made a component which you can add to any object you want. No need to extend Unitys native components. One caveat though: if another code is listening for onPointer events then these will be triggered even while dragging. I’ve added a “DisableEventTriggerWhileDragging” bool to control that.

Btw.: if you only need onClick events from a button then simply remove the EventTrigger component from it and all scroll and drag events will work out of the box.

using UnityEngine;
using UnityEngine.EventSystems;
using static UnityEngine.EventSystems.ExecuteEvents;

namespace kamgam
{
   /// <summary>
   /// Bubbles events to the parent. Use this to overcome EventTriggers which stop scroll and drag events from bubbling.
   ///
   /// If an EventTrigger component is attached and other code is listening for
   /// onPointer events then these will NOT be triggered while dragging if DisableEventTriggerWhileDragging
   /// is true.
   /// </summary>
   public class UiScrollRectEventBubbling : MonoBehaviour,
                                       IBeginDragHandler,
                                       IDragHandler,
                                       IEndDragHandler,
                                       IScrollHandler
                                      
   {
       [Tooltip("Should the scroll and drag events be forwarded (bubble up) to the parent?")]
       public bool Bubble = true;

       [Tooltip("Stop EventTriggers from executing events while dragging?")]
       public bool DisableEventTriggerWhileDragging = true;

       protected EventTrigger eventTrigger;
       public EventTrigger EventTrigger
       {
           get
           {
               if (eventTrigger == null)
               {
                   eventTrigger = this.GetComponent<EventTrigger>();
               }
               return eventTrigger;
           }
       }

       protected bool dragging = false;

       protected void HandleEventPropagation<T>(Transform goTransform, BaseEventData eventData, EventFunction<T> callbackFunction) where T : IEventSystemHandler
       {
           if (Bubble && goTransform.parent != null)
           {
               ExecuteEvents.ExecuteHierarchy(goTransform.parent.gameObject, eventData, callbackFunction);
           }
       }

       public void OnScroll(PointerEventData eventData)
       {
           HandleEventPropagation(transform, eventData, ExecuteEvents.scrollHandler);
       }

       public void OnBeginDrag(PointerEventData eventData)
       {
           HandleEventPropagation(transform, eventData, ExecuteEvents.beginDragHandler);

           dragging = true;
           if (DisableEventTriggerWhileDragging && EventTrigger != null)
           {
               EventTrigger.enabled = false;
           }
       }

       public void OnDrag(PointerEventData eventData)
       {
           HandleEventPropagation(transform, eventData, ExecuteEvents.dragHandler);
       }

       public void OnEndDrag(PointerEventData eventData)
       {
           HandleEventPropagation(transform, eventData, ExecuteEvents.endDragHandler);

           dragging = false;
           if (DisableEventTriggerWhileDragging && EventTrigger != null)
           {
               EventTrigger.enabled = true;
           }
       }

       /// <summary>
       /// If the object is disabled while being dragged then the EventTrigger would remain disabled.
       /// </summary>
       public void OnDisable()
       {
           if (DisableEventTriggerWhileDragging && dragging && EventTrigger != null)
           {
               dragging = false;
               EventTrigger.enabled = true;
           }
       }
   }
}

Maybe it will be useful.

3 Likes

Here’s my solution.

    public Scrollbar scrollbar;
    public float scrollSpeed = .05f;

    void Update()
    {
        if(Input.mouseScrollDelta.y != 0)
        {
            scrollbar.value += Input.mouseScrollDelta.y * scrollSpeed;
        }
        if(scrollbar.value > 1)
        {
            scrollbar.value = 1;
        }
        else if (scrollbar.value < 0)
        {
            scrollbar.value = 0;
        }
    }
1 Like

This code was exactly what I needed. Thanks so much for passing it along!

1 Like

Six years later, still coming for this.

1 Like

Same bro

Seven - years - later…

Your solution works. Thanks.

Not suited for elements with Event Triggers. Still don’t know how to fix this

Still having this problem in 2022.The solution above is a great fix but when I dragged on a button and released on the same button, it counted as a click - so I fixed that. Here’s the code:
( Add this code to the script provided by sevensails )

    public static bool isDragging { get; private set; }

// these two methods are already in the script, just add the lines with isDragging
    public void OnBeginDrag(PointerEventData eventData)
    {
        MainScroll.OnBeginDrag(eventData);
        isDragging = true;
    }
    public void OnEndDrag(PointerEventData eventData)
    {
        MainScroll.OnEndDrag(eventData);
        isDragging = false;
    }

And then in the function your buttons use, add this return check:

 if (FixScrollRect.isDragging) return;

You are my hero.

And you too!

Had the same issue. Hover and Exit events fired from the Event Trigger Component were blocking the ScrollView.

Solved by removing the Event Trigger Component and having a simple custom script with the implementation of IPointerEnterHandler and IPointerExitHandler interfaces. Works great. It doesn’t block the ScrollView.

using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;

public class HoverUnhover : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
    public UnityEvent Hovered;
    public UnityEvent Unhovered;

    public void OnPointerEnter(PointerEventData eventData)
    {
        Hovered.Invoke();
    }

    public void OnPointerExit(PointerEventData eventData)
    {
        Unhovered.Invoke();
    }
}

Thanks from the future