child objects blocking scrollrect from scrolling

i am making a desktop application, i would like the user to be able to scroll the scrollrect by clicking and dragging, even over other objects with event system components.

Basically:
user can click on the child objects inside the scroll rect with a click event
if user clicks down and drags, scroll rect should scroll and click up should cancel

sort of looking for mobile style functionality.

any thoughts?
Thanks

I have exactly the same problem and have not been able to solve it. Attached a test scene to illustrate the problem.

I suppose many people are building some kind of drag-able menus full of buttons, maybe too trivial and we are overlooking something?

2024599--131032--SliderToggleTest.zip (194 KB)

2 Likes

bump? anything on this? its a rather big issue for my use case, if the UI system doesnt offer this i may have to abandon it

I've got a scroll rect full of buttons and it scrolls just fine by dragging (at least on Windows).

Is your content made out of Button components or EventTrigger components? My understanding is that EventTrigger captures all events, but Buttons should only capture pointer enter/exit/click, not drag.

3 Likes

right, im seeing if the button has a OnClick() function, but i need more functionality then OnClick. i need to call methods besides changing color on mouse over and exit as well, so from what i see i need to add an EventTrigger, and thats actually where im seeing the problem.

any way to call functions on mouse enter / exit on buttons without event triggers?

Yes--you can write your own component that implements the IPointerEnterHandler and IPointerExitHandler interfaces. As long as you don't implement the drag handlers, drag events should pass right through.

5 Likes

thank you Antistone exactly what i was looking for

Do you mind posting simple example of your implementation? Would be really helpful.

sure, theres a few small steps to take to get the methods to work
Im using C#, im not sure on exact translation if your using javascript

first, import event systems

using UnityEngine.EventSystems;

then add event types to your class (this will change depending on the type of events you are using, ignore 'InfinityScrollCell', that is my base class, yours will most likely say 'MonoBehaviour' )

public class TimeLineCell : InfinityScrollCell,IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler,IPointerDownHandler

finally implement the methods

public void OnPointerEnter (PointerEventData eventData)
    {
        mouseOver = true;
        highlightCell (true);
    }

    public void OnPointerExit (PointerEventData eventData)
    {
        mouseOver = false;
        highlightCell (false);
    }

    public void OnPointerDown (PointerEventData eventData)
    {
        if (parentScrollRect.scrollRect.velocity.magnitude > 0) {
            canClick = false;
        }
    }

    public void OnPointerClick (PointerEventData eventData)
    {
        if (canClick == true) {
                  // add code for click here
        }
        canClick = true;
    }

as a tip, i recommend blocking the click method if the scrollRect is moving when the user clicks down. this way the first click will stop the scroll rect from moving, second click will be selecting the button/object. you can see some sample logic in OnPointerDown and OnPointerClick

one nice thing about this is this can be added to any rectTransform, so you dont have to use button objects, however, i have not done any hit testing with overlapping views

2 Likes

Whoa cool, thanks for such a fast answer. I do work mainly with C# but am rather newcomer when it comes to this kind of tweaking. Will try to use your instructions!

no problem, you may want to mess with the threshold for clicking. in my sample i have it set to '0' but im seeing sometimes even when the scrollRect.velocity.magnitude looks to be still, its returning slightly above zero, im finding '0.1' to be more stable

Im now finally trying to follow your instructions. I suppose "highlightCell" etc are somehow based on the uGUI stuff on the background, sorry for my ignorance, but I get following error with your code: Assets/DragHandler.cs(14,17): error CS0103: The name `mouseOver' does not exist in the current context. And same error for highlightCell etc.

Here is my full code:

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using UnityEngine.EventSystems;

public class SkipDragHandler : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler,IPointerDownHandler
{

    private bool canClick;


    public void OnPointerEnter (PointerEventData eventData)
    {
        mouseOver = true;
        highlightCell (true);
    }

    public void OnPointerExit (PointerEventData eventData)
    {
        mouseOver = false;
        highlightCell (false);
    }

    public void OnPointerDown (PointerEventData eventData)
    {
        if (parentScrollRect.scrollRect.velocity.magnitude > 0) {
            canClick = false;
        }
    }

    public void OnPointerClick (PointerEventData eventData)
    {
        if (canClick == true) {
            // add code for click here
            Debug.Log ("OnPointerClick detected!");
        }
        canClick = true;
    }

}

If I understand correctly, canClick is your own stuff, so I just created variable for it and it is ok. But how to proceed with the rest?

mouseOver and highlightCell is also own stuff just delete them and fill the methods with your own stuff... you don't need the variables, the Events (OnPointerEnter , OnPointerExit etc) get triggered anyway

this is enough

public class YourClass: MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler,IPointerDownHandler
{
public void OnPointerEnter (PointerEventData eventData)
    {
          //do stuff
    }
    public void OnPointerExit (PointerEventData eventData)
    {
          //do more stuff
    }
    public void OnPointerDown (PointerEventData eventData)
    {
         //do wicked stuff
    }
    public void OnPointerClick (PointerEventData eventData)
    {
          //do random stuff
    }
}
1 Like

Attached now the version including the code from pat_sommer and PBeast fixes. Unfortunately it still is not working. I am afraid that my lack of working with the event system in this way does not allow me to see the obvious. PBeast would you mind taking a look at the example project and see where I go wrong?

Ultimately I try to use this with toggle on top of the scroll rect. But even disabling the toggle and just using image component with rect transform does not make the drag handler "go through" the button.

2088777--136602--SliderToggleTest.zip (526 KB)

Am i guessing right that you want to have your toggle clickable but you DON'T want it to block drags? So that you can drag the scrollRect even if you begin the drag over the toggle?

Yes, exactly that :)

hm okay, i never did this before and as Antistone mentioned the dragevent SHOULD pass right through but actually it does not o.0. Sorry i'm no master so i don't know what we are doing wrong here or if this is a bug.

But i can say that you cant add a SkipDrag script and add it to you toggle, your toggle blocks the drag, so you have to write your own toggle class. I tried but i think even the Image component blocks the dragEvent from passing through :(

Sorry for being no help :'(

No worries PBeast! I'm very grateful for the fact that you even try to help! I will keep studying how to write this toggle by myself :)

Im now just trying to simplify everything to make the Drag event go through the button. Apparently no matter what even if I dont have drag on the script, the image itself will block raycast and it is simply not possible for the scrollrect detect the drag?

Edit: Now I got it to work, the toggle MUST be as child to the ScrollRect for it to go through and I had to naturally remove the default implementation of the events to be replaced with my own version that did not have drag handling. For the OnValueChanged that seems to work just fine as is.

Attachment: Example project with working solution and example of an custom OnPointerDown event.

2092347--137296--SliderToggleTest.zip (535 KB)

It seems this is still an issue. I have a Scroll rect with a bunch of buttons in it. If you use the scroll wheel and the pointer is over a button or an image without a CanvasGroup with blocksRaycasts=false then it prevents scrolling. When I used to write my own UI for a different engine the scroll rect would always check for it's own interaction first and then the elements within it. This seems like a major flaw in the UI system! Hopefully Unity will address this. And thanks for the hack, I'll give it a go.

3 Likes