IsPointerOverGameObject not working with touch input

I’m using IsPointerOverGameObject() inside OnMouseDown() to detect whether the player is clicking/touching a GUI button that happens to be over the game object. If that’s the case, the function ignores the remainder of the code in OnMouseDown() by immediately returning:

void OnMouseDown()
{
    // Detect mouse event
    if (EventSystem.current.IsPointerOverGameObject())
    {
        print("return mouse");
        return;
    }
    // Detect touch event
    foreach (var touch in Input.touches)
    {
        if (EventSystem.current.IsPointerOverGameObject(touch.fingerId))
        {
            print("return touch");
            return;
        }
    }

    // Other code...

}

In the editor, this works as expected when clicking a GUI button over the game object: the function prints “return mouse” and returns. On my Android device, the GUI object is interacted with, but the OnMouseDown() function doesn’t return!

How can I fix this problem?

After some hours, I managed to find a work around:

private bool IsPointerOverUIObject() {
    PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current);
    eventDataCurrentPosition.position = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
    List<RaycastResult> results = new List<RaycastResult>();
    EventSystem.current.RaycastAll(eventDataCurrentPosition, results);
    return results.Count > 0;
}

Taken from this thread:

http://forum.unity3d.com/threads/ispointerovereventsystemobject-always-returns-false-on-mobile.265372/

I include that code and then just substitute EventSystem.current.IsPointerOverGameObject() with IsPointerOverUIObject() and it works.

Hope this helps someone.

https://docs.unity3d.com/ScriptReference/EventSystems.EventSystem.IsPointerOverGameObject.html

you can use this code to check touch & mouse

/// <returns>true if mouse or first touch is over any event system object ( usually gui elements )</returns>
public static bool IsPointerOverGameObject(){
	//check mouse
	if(EventSystem.current.IsPointerOverGameObject())
		return true;
	
	//check touch
	if(Input.touchCount > 0 && Input.touches[0].phase == TouchPhase.Began ){
		if(EventSystem.current.IsPointerOverGameObject(Input.touches[0].fingerId))
			return true;
	}
	
	return false;
}

For future visitors, as far as I know, both of the solutions above generates quite a lot of garbage. Also one of them only supports single touch.

So as far as I can tell, I think the solution should be something like:

public static bool IsPointerOverGameObject()
{
    // Check mouse
    if (EventSystem.current.IsPointerOverGameObject())
    {
        return true;
    }
  
    // Check touches
    for (int i = 0; i < Input.touchCount; i++)
    {
        var touch = Input.GetTouch(i);
        if(touch.phase == TouchPhase.Began)
        {
            if (EventSystem.current.IsPointerOverGameObject(touch.fingerId))
            {
                return true;
            }
        }
    }
    
    return false;
}
bool inTouch;
if (inTouch = Input.touchCount > 0)
    touch = Input.GetTouch(0);
if (
#if !UNITY_EDITOR && (UNITY_ANDROID || UNITY_IOS)
    inTouch && touch.phase == TouchPhase.Began && EventSystem.current.IsPointerOverGameObject(touch.fingerId)
#else
    Input.GetMouseButtonDown(0) && EventSystem.current.IsPointerOverGameObject()
#endif
    )
{
    // Do something
}