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
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
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.
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.
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.
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.
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
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.
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();
}
To anyone who cares I have found what “causes” the issue. Inside the BaseInputModule.cs inside the
HandlePointerExitAndEnter method:
currentPointerData.pointerEnter = newEnterTarget;
if (newEnterTarget != null)
{
Transform t = newEnterTarget.transform;
while (t != null)
{
// if (t.gameObject != newEnterTarget && t.gameObject == commonRoot)
//{
// break;
//}
currentPointerData.reentered = t.gameObject == commonRoot;
ExecuteEvents.Execute(t.gameObject, currentPointerData, ExecuteEvents.pointerEnterHandler);
ExecuteEvents.Execute(t.gameObject, currentPointerData, ExecuteEvents.pointerMoveHandler);
currentPointerData.hovered.Add(t.gameObject);
if (commonRoot != null && commonRoot.transform == t)
break;
t = t.parent;
}
}
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…
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.
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