Search Unity

Problem with IPointerEnterHandler IPointerExitHandler and SetActive

Discussion in 'UGUI & TextMesh Pro' started by R1PFake, Feb 5, 2022.

  1. R1PFake

    R1PFake

    Joined:
    Aug 7, 2015
    Posts:
    542
    I already found a few posts about OnPointerExit not being called when the GameObject is disabled (or destroyed) and for some reason Unity doesn't want to change this behavior. The other posts suggest to move the logic to OnDisable and/or OnDestroy but that doesn't work in my case.

    My case:
    I have a UI object which implements both interfaces and changes the background color while the pointer is inside the object, so in OnPointerEnter I set the "hover" color and in OnPointerExit it reset it back to the original color.

    The object can be disabled and enabled while the pointer is still over the object.

    As the other posts mention I can just reset the color during OnDisable as a workaround. But my issue is if I then enable the object again while the pointer is still over the object, OnPointerEnter will also not be called, so the object will not show my "hover" color again.

    My current workaround is to use OnEnable and manually check (with EventSystem Raycast) if the pointer is still over the same object and then show the hover color again.

    This seems to work for now, but I think it's silly that we have to do all the manual extra work.

    I can't be the only one who uses these interfaces for hovering color. So my question is, did anyone else have this exact issue and how did you fix it? I hope there is a better way to fix it than my manual raycast check
     
  2. R1PFake

    R1PFake

    Joined:
    Aug 7, 2015
    Posts:
    542
    Bump, I downloaded the new 2021 LTS version and still the same behavior.

    Does no one else notice or care about this behavior?

    There is no clean way to implement a simple highlight color or anything like that with the Pointer Enter/Exit events, because the methods don't get called if the object is disabled/enabled without moving the mouse.

    Any kind of ingame menu which can be toggled with a keyboard should have this issue.

    But either people don't notice it or have some obvious solution that Im missing?

    Update: I found the "issue"

    It turns out that OnPointerEnter IS called again after disable -> enable, if the mouse is still inside the object, but only if there is at least one frame difference between the disable -> enable

    So simple case:
    - disable object
    - use OnDisable to call the same method / logic as OnPointerExit
    - wait at least one frame (which would be the usual case for a keypress menu anyways)
    - enable the object again
    - OnPointerEnter will be called again (if the mouse is still inside the object)

    Advanced case, where you disable / enable the object in the same frame and you are 100% sure that the object will be disabled / enabled at the same position:
    - disable object
    - use OnDisable to call the same method / logic as OnPointerExit AND store the current frame count / pointer state
    - enable the object (in the same frame and at the same position)
    - use OnEnable now manually check if the object was enabled again in the same frame (by comparing the frameCount) and check if the pointer was inside the object during disable, of both this true then this is the "special case" and you can manually call the OnPointerEnter logic in this case
     
    Last edited: Apr 14, 2022
    yxd3300 likes this.
  3. DenisWASD

    DenisWASD

    Joined:
    Dec 10, 2016
    Posts:
    9
    I've got a little different issue with IPointerHandler interfaces in 2021 LTS.

    I've used 2021.1 for a while and I had a UI panel with a button inside it, as a child.

    Both the panel and the button have their raycasts on, since both should be interactable.

    I have a script with IPointerEnterHandler and IPointerExitHandler attached on the panel. Whenever you hover over the panel, the button inside it appears (so you can click it).

    Now in 2021.1 it worked perfectly, I could hover over the panel and then click on the button. The IPointerEnterHandler considered the button raycast as its own - it was always like that.

    However, in 2021.3, this seems to have changed. The same script and same UI no more work like that. The IPointerEnterHandler no more considers the button as its own raycast. Therefore, if you hover over the panel, it appears, but the moment you hover over the button it starts flickering. The button turns on and off every frame.

    The issue is that when you hover over the button, you no longer hover over the panel, therefore the button disappears. But then you're again hovering over the panel, so the button reappears. A loop is created.
     
  4. RoosterMai

    RoosterMai

    Joined:
    Nov 6, 2016
    Posts:
    8
    just like DenisWASD says, I also find this problem, when hover child obj, it will trigger parent's IPointerExitHandler, I don't if it is a bug or Unity just change this behaviour.
     
    DenisWASD likes this.
  5. YAMASU

    YAMASU

    Joined:
    Nov 29, 2020
    Posts:
    2
    I have same issue too.
     
    DenisWASD likes this.
  6. Aravind_B_SST

    Aravind_B_SST

    Joined:
    May 16, 2022
    Posts:
    5
    Facing the same issue as DenisWASD described.

    Lets take the following as an example, Child Rect is inside of Parent Rect.
    A script is attached to parent game object to capture mouse pointer enter/exit events to enable/disable the child on hover or Highlight parent game object on hover.

    Screenshot_1.png

    In 2019.4 (LTS) and 2020.3 (LTS) : OnPointerEnter and OnPointerExit is invoked when the mouse pointer enter/exit the parent. Nothing will happen when mouse pointer enter/exit the child.
    (Pointer Exit is not invoked when mouse pointer is over child, considering both parent and child as a single element)

    In 2021.2 : OnPointerEnter and OnPointerExit is invoked whenever the mouse pointer enter/exit both parent and child.
    (Pointer Exit followed by Pointer Enter are invoked when mouse pointer is over child, considering parent and child as a individual element)

    In 2021.3 (LTS) : OnPointerEnter is invoked on entering parent and OnPointerExit is invoked on entering child. But OnPointerEnter is not invoked followed by OnPointerExit like it was on 2021.2.

    This constant change in behaviour affects the implementations in our application.
     
    Last edited: May 24, 2022
    breylinlee, restush96 and DenisWASD like this.
  7. DenisWASD

    DenisWASD

    Joined:
    Dec 10, 2016
    Posts:
    9
    I have reported the issue to Unity 2 weeks ago, but they still didn't reach back to me. I guess this bug is still in review.
     
  8. Aravind_B_SST

    Aravind_B_SST

    Joined:
    May 16, 2022
    Posts:
    5
    Thanks DenisWASD for your response. Could you please share the bug details if possible, so that I could also follow the progress.
     
    DenisWASD likes this.
  9. unity_ctg0ujCJYRi52g

    unity_ctg0ujCJYRi52g

    Joined:
    Jun 1, 2020
    Posts:
    11
    Hi,
    I have the same problem.
    I use OnPointerEnter to display Inventory Items tooltips in a diablo style game.
    Everything was ok in 2020LTS but when I upgraded my project to 2021LTS problems began.
    I have this issue in both 2021.3.1f1 and 2021.3.2f1
     
    Aravind_B_SST and DenisWASD like this.
  10. Simpowitch

    Simpowitch

    Joined:
    Nov 13, 2018
    Posts:
    14
    I have reported the same issue as DenisWASD to unity as well last week. This is devestating to our project that has a few hundred buttons and toggles that now breaks our tooltip system and as well as Unitys built in Highlight and sprite-swap systems on buttons and toggles.

    -using LTS 2021.3.2f1
     
  11. dhologroup

    dhologroup

    Joined:
    Mar 8, 2018
    Posts:
    1
    I don't know if this helps you guys or is what is causing your problem but in reading your posts I believe I was having the same issue and was able to solve it with the code below just now. I have the same script on both the parent and child object that implements IPointerEnterHandler. I found that the PointerEventData object contains information about the original gameobject that tiggers OnPointerEnter. if the original caller is the parent gameobject then the if statement in OnPointerEnter is satisfied. When the child gameobject triggers the OnPointerEnter event then the below if statement condition is met yet when the child gameobject automatically triggers the parent gameobject's OnPointerEnter the if statement does not execute essentially stopping the bubbling up "feature". I hope this helps you guys as I was struggling on how to prevent the bubbling as we too use many child buttons that implement the same InteractiveButton script.

    public class InteractiveButton : MonoBehaviour, IPointerClickHandler, IPointerEnterHandler, IPointerExitHandler
    {
    private float pushTimeInSec = 1.0f; //Makes sure the button is pushed for 1 second
    private UnityEvent onPush = null; //Registered in the Inspector

    public UnityEvent OnPush
    {
    get { return onPush; }
    set { onPush = value; }
    }

    public void OnPointerEnter(PointerEventData eventData)
    {
    if (eventData.pointerEnter.ToString() == this.gameObject.ToString())
    StartCoroutine(Push());
    }

    private IEnumerator Push()
    {
    yield return new WaitForSeconds(pushTimeInSec);
    OnPush.Invoke();
    }

    }
     
    DenisWASD likes this.
  12. Zeejfps

    Zeejfps

    Joined:
    May 20, 2017
    Posts:
    8
    Do you have a link to the Issue Tracker? It would be nice if we can go in and Up Vote it.
    Because this is breaking stuff for me as well
     
  13. Zeejfps

    Zeejfps

    Joined:
    May 20, 2017
    Posts:
    8
    To anyone who cares I have found what "causes" the issue. Inside the BaseInputModule.cs inside the
    HandlePointerExitAndEnter method:

    Code (CSharp):
    1.  
    2. currentPointerData.pointerEnter = newEnterTarget;
    3. if (newEnterTarget != null)
    4. {
    5.     Transform t = newEnterTarget.transform;
    6.  
    7.     while (t != null)
    8.     {
    9.         // if (t.gameObject != newEnterTarget && t.gameObject == commonRoot)
    10.         //{
    11.         //    break;
    12.         //}
    13.         currentPointerData.reentered = t.gameObject == commonRoot;
    14.         ExecuteEvents.Execute(t.gameObject, currentPointerData, ExecuteEvents.pointerEnterHandler);
    15.         ExecuteEvents.Execute(t.gameObject, currentPointerData, ExecuteEvents.pointerMoveHandler);
    16.         currentPointerData.hovered.Add(t.gameObject);
    17.  
    18.         if (commonRoot != null && commonRoot.transform == t)
    19.             break;
    20.         t = t.parent;
    21.     }
    22. }
    23.  
    Comment out the 4 lines like I have. I am still not 100% certain why the logic is the way it is and why they want to ignore the commonRoot. But I know this is in fact the issue because first reentered can never be set to true because the loop will break when t.gameObject is the commonRoot, and the pointerEnterHandler is never executed on the common root, only on child game objects which might not have the component that implement the IPointerEnterHandler interface.

    What really doesn't make sense is why the official github page has different code than the one in the v1.0 of UI package. The code in the link is for the 2019 version and there doesn't appear to be a branch for anything newer...
    https://github.com/Unity-Technologi...I/EventSystem/InputModules/BaseInputModule.cs
     
    Last edited: May 31, 2022
    Kennai and Benfont like this.
  14. Benfont

    Benfont

    Joined:
    Nov 11, 2017
    Posts:
    21
    Yep, this solves the issue for me - thanks a lot!!!
     
  15. andrewpey

    andrewpey

    Joined:
    Sep 21, 2014
    Posts:
    10
    We've also stumbled upon this issue after upgrading to 2021.3 (LTS) from 2020.3 (LTS).

    Did they open an issue for that yet?
     
  16. restush96

    restush96

    Joined:
    May 28, 2019
    Posts:
    145
    I have a feeling that this will be treat as "by design" from 2021.3.
     
  17. Elringus

    Elringus

    Joined:
    Oct 3, 2012
    Posts:
    483
  18. unity_ctg0ujCJYRi52g

    unity_ctg0ujCJYRi52g

    Joined:
    Jun 1, 2020
    Posts:
    11
    Hi,
    I cannot access this method.
    For me its just:
    BaseInputModule[from metadata]
    protected void HandlePointerExitAndEnter(PointerEventData currentPointerData, GameObject newEnterTarget);
    Do I need f.eg. Unity Pro or are you using some specific IDE?
    Can you provide any advice on how to modify it, as it is utmost annoying to work when windows are flickering all the time.
     
  19. Benfont

    Benfont

    Joined:
    Nov 11, 2017
    Posts:
    21
    Find the script in your Unity project and right click it and open its containing folder.
    Once there open it with a different IDE that you normally use for Unity. That worked for me
     
  20. unity_ctg0ujCJYRi52g

    unity_ctg0ujCJYRi52g

    Joined:
    Jun 1, 2020
    Posts:
    11
    Yes thanks, this way I can see its content still, after I comment out these lines and open projects it goes:
    - import
    - automatically reverts changes
    and I'm back to where I started.

    Is there some "protect unity files" setting that I'm not aware of?
     
  21. DenisWASD

    DenisWASD

    Joined:
    Dec 10, 2016
    Posts:
    9
    Last edited: Jun 10, 2022
  22. DenisWASD

    DenisWASD

    Joined:
    Dec 10, 2016
    Posts:
    9
    Looks like now you will need to do something like this:
    Code (CSharp):
    1. public void OnPointerExit (PointerEventData eventData)
    2. {
    3.         if (!eventData.fullyExited) return;
    4.         // Do stuff you've always done
    5. }
    I've checked it now on my test project and it works!
     
    Last edited: Jun 10, 2022
  23. aliasgar5253

    aliasgar5253

    Joined:
    Nov 1, 2020
    Posts:
    4
    Thanks a lot! This works great!
     
  24. Simpowitch

    Simpowitch

    Joined:
    Nov 13, 2018
    Posts:
    14
    Unfortunately this does not solve all issues. Unitys event on Buttons, Toggles and Event triggers will still not function as they used to (responding correctly with sprite-swaps etc.)

    This also seems to not function 10% of the time if you move your mouse too quickly over the edge of childed objects with raycast on, and many other cases. But sometimes - this code below that you provided - helps. But far from all cases sadly. And yes it's considered a bug, I have a bugreport that they have reproduced and have confirmed and weill come back when they have a fix for it.

     
  25. andrewpey

    andrewpey

    Joined:
    Sep 21, 2014
    Posts:
    10
    Do you have an issue number for that so we can track it too?
     
  26. unity_ctg0ujCJYRi52g

    unity_ctg0ujCJYRi52g

    Joined:
    Jun 1, 2020
    Posts:
    11
    Thank You,
    works like a charm.
     
  27. AlexisTerraf

    AlexisTerraf

    Joined:
    Oct 31, 2016
    Posts:
    6
    Like Simpowitch I've tested it and it doesn't work all the time. It's possible to exit too fast or if you exit over a child and it does not trigger the "fullyExited".

    This is really annoying and we cannot update to LTS due to this bug :(
     
  28. tbg10101_

    tbg10101_

    Joined:
    Mar 13, 2011
    Posts:
    192
    Adding my voice here because I am similarly affected after updating 2020.3 to 2021.3.
     
  29. karliss_coldwild

    karliss_coldwild

    Joined:
    Oct 1, 2020
    Posts:
    602
    One more workaround that which works slightly better than checking fullyExited flag, but isn't universally applicable is to to disable "raycastTarget" option for all the child objects. For TextMeshPro - Text(UI) components "raycas target" option is hidden under "Extra settings". This works quite well for simple buttons with icon or text on top where all the child elements are inside parent, but isn't applicable to situation where child objects are partially outside the bounds of parent like popout menus.

    Also here are a few more forum posts discussing the same change in unity behavior:
    https://forum.unity.com/threads/eventsystem-unexpecteldy-calling-ipointerexit-in-2021-3-1f1.1274252/
    https://forum.unity.com/threads/unity-2021-2-17f1-break-pointer-events.1257951/#post-8115503
     
  30. andrewpey

    andrewpey

    Joined:
    Sep 21, 2014
    Posts:
    10
    Luckily, it was reverted to the old behavior in the latest LTS (2021.3.6):

     
    Spectragate likes this.
  31. Spectragate

    Spectragate

    Joined:
    Jan 23, 2022
    Posts:
    37
    Nice that this is being reverted, too bad we have to wait for 2022.2.X for the fix.

    For now the workaround by @DenisWASD does seem to be working enough to get my tests to pass.
     
  32. papirosnik

    papirosnik

    Joined:
    Feb 17, 2012
    Posts:
    6
    >>Luckily, it was reverted to the old behavior in the latest LTS (2021.3.6):

    Unfortunately, it seems not fully reverted.
    I've got not clickable buttons in Unity 2021.3.6 if they belongs to a nested canvas and that canvas has "Override sorting" switched off.
    The only solution is to set "override sorting" for every nested canvas on.
    But this may cause other side effects on pretty big project...
    So I ended up by downgrading to Unity 2021.2.15 (the last version we used without any troubles before trying 2021.3.6). Everything (in regards of pointer clicks) works fine there.
    I double checked and upgraded to 2021.3.6 again - without any changes except version, ui buttons on nested canvases (without "override sorting") stopped working .
    EventSystem shows nothing in pointerEnter and pointerClick fields.
     
  33. SnooksV3

    SnooksV3

    Joined:
    Dec 11, 2018
    Posts:
    11
    This is a nightmare. Just updated my project, literally every button is broken.

    Code (CSharp):
    1. if (!eventData.fullyExited) return;
    This works but not for nested elements. Hovering back to it's parent doesn't trigger.

    Via. 2022.1.10f1
     
    Last edited: Jul 29, 2022
  34. karliss_coldwild

    karliss_coldwild

    Joined:
    Oct 1, 2020
    Posts:
    602
  35. Nest_g

    Nest_g

    Joined:
    Jun 18, 2019
    Posts:
    151
    Is very weird why Unity API have not a over event for the UI, actual Enter and Exit events are not accurate, for example, you active a panel and when this happens you cant know if the pointer is in or out of the panel.