1. We've introduced thread tags, search within a thread and similar thread search. Read more here.
    Dismiss Notice
  2. Learn how you'll soon be able to publish your games to China in four simple steps with Xiaomi. Sign up now for early access.
    Dismiss Notice
  3. Get further faster with the Unity Plus Accelerator Pack, free for new Unity Plus subscribers for a limited time. Click here for more details.
    Dismiss Notice
  4. We've released our first Timeline Experimental Preview, our new tool for creating cutscenes and more! To check it out click here.
    Dismiss Notice
  5. Unity 5.5 is now released.
    Dismiss Notice
  6. Check out all the fixes for 5.5 in patch releases 1 & 2.
    Dismiss Notice
  7. Unity 5.6 beta is now available for download.
    Dismiss Notice

IsPointerOverEventSystemObject always returns false on mobile

Discussion in 'Unity UI & TextMesh Pro' started by adhdchris, Aug 29, 2014.

  1. adhdchris

    adhdchris

    Joined:
    Nov 13, 2013
    Posts:
    36
    Calling IsPointerOverEventSystemObject works great in unity editor and standalone builds but on mobile devices (Android to be more specific) it always returns false.
    Is this a bug or am I missing something here?
     
  2. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    1,885
    IsPointerOverEventSystemObject takes an int for the touch id. Mouse is the default (-1) use touch id's to figure out if a certain finger is over a managed object.
     
    Ahmadhp, SomeAlexander and adhdchris like this.
  3. adhdchris

    adhdchris

    Joined:
    Nov 13, 2013
    Posts:
    36
    Thanks Tim!
    I had no idea IsPointerOverEventSystemObject took a touch id, I'll give it another shot.
     
  4. Supergeek

    Supergeek

    Joined:
    Aug 13, 2010
    Posts:
    55
    Is there a reference as to what touch ids are possible? Like, would 0 be first touch or something?

    Also, wouldn't it be easier to just not propagate touches through stuff, or make it a toggle?
     
  5. phil-Unity

    phil-Unity

    Unity UI Lead Developer Unity Technologies

    Joined:
    Nov 23, 2012
    Posts:
    1,045
    No references as of yet but -1 if mouse and then the rest are the ids of Touch.fingerId
     
  6. Supergeek

    Supergeek

    Joined:
    Aug 13, 2010
    Posts:
    55
    Anyone care to post a working example?
     
  7. adhdchris

    adhdchris

    Joined:
    Nov 13, 2013
    Posts:
    36
    The most basic example would be something like this:
    Code (CSharp):
    1. void Update ()
    2.         {
    3.                 if (Input.touchCount > 0 && Input.GetTouch (0).phase == TouchPhase.Began) {
    4.                         if (!EventSystemManager.currentSystem.IsPointerOverEventSystemObject (Input.GetTouch (0).fingerId)) {
    5.                                 //Handle Touch
    6.                         }
    7.                 }
    8.         }
     
    HaroldBrainz and Supergeek like this.
  8. Bivrost

    Bivrost

    Joined:
    Mar 26, 2014
    Posts:
    80
    Since 4.6 Beta 19, IsPointerOverEventSystemObject does not work anymore. Is this by design or just a bug?

    This is what we were doing before to detect button touches:
    Code (csharp):
    1.  
    2. // ...
    3. EventSystem eventSystem = EventSystem.current;
    4. return ( eventSystem.IsPointerOverEventSystemObject( fingerId )
    5.     && eventSystem.currentSelectedObject != null );
    6.  
    ...were fingerId is something in the range between -1 (mouse button) and Touch.fingerId.

    The console says: "UnityEngine.EventSystems.EventSystem' does not contain a definition for `IsPointerOverEventSystemObject' and no extension method `IsPointerOverEventSystemObject' of type `UnityEngine.EventSystems.EventSystem' could be found..."

    The code worked fine with 4.6 Beta 17 and 18. Is there a workaround?
     
    dude4004 likes this.
  9. adhdchris

    adhdchris

    Joined:
    Nov 13, 2013
    Posts:
    36
    I believe it's been changed to IsPointerOverGameObject(fingerId).
     
    Bivrost likes this.
  10. Bivrost

    Bivrost

    Joined:
    Mar 26, 2014
    Posts:
    80
    Thank you for the quick reply, adhdchris :) I'll try that later. Couldn't find the information anywhere.
     
  11. gruddlebug

    gruddlebug

    Joined:
    Mar 11, 2013
    Posts:
    65
  12. adhdchris

    adhdchris

    Joined:
    Nov 13, 2013
    Posts:
    36
  13. gruddlebug

    gruddlebug

    Joined:
    Mar 11, 2013
    Posts:
    65
    Very true!
     
  14. Bivrost

    Bivrost

    Joined:
    Mar 26, 2014
    Posts:
    80
    That worked. Thanks again. Actually, I read the release notes several times but couldn't find any information about this change. o_O

    EventSystem.currentSelectedObject is also not working anymore. It's called EventSystem.currentSelectedGameObject now.

    So for the sake of completeness, the code to test for UI button touches changed to:
    Code (csharp):
    1. bool IsPointerOverGameObject( int fingerId )
    2. {
    3.     EventSystem eventSystem = EventSystem.current;
    4.     return ( eventSystem.IsPointerOverGameObject( fingerId )
    5.         && eventSystem.currentSelectedGameObject != null );
    6. }
     
  15. Aurecon_Unity

    Aurecon_Unity

    Joined:
    Jul 6, 2011
    Posts:
    217
    Hi Bivrost

    I've been having issues with getting the UI to block raycasts from touch input (on android) and this thread looks like the best lead I have so far to solve it. Here was the thread I made:

    http://forum.unity3d.com/threads/how-to-make-ui-block-raycats-mobile.271978/#post-1820891

    I would really appreciate getting a bit of your expertise on the code you provided above - I'm not quite sure where to put in in my code. I think it's the answer to my problems, I just can't put the pieces in place!

    Thanks a lot
     
  16. adhdchris

    adhdchris

    Joined:
    Nov 13, 2013
    Posts:
    36
    mickyg, just combine my previous answer on getting the touch id with Bivrost's method (use foreach if you need multitouch):
    Code (CSharp):
    1.  
    2. void Update ()
    3. {
    4.                if (Input.touchCount > 0 && Input.GetTouch (0).phase == TouchPhase.Began) {
    5.                         if (IsPointerOverGameObject (Input.GetTouch (0).fingerId)) {
    6.                                 Debug.Log("Hit UI, Ignore Touch");
    7.                         } else {
    8.                                 Debug.Log("Handle Touch");
    9.                         }
    10.                }        
    11. }
    12.  
    13. bool IsPointerOverGameObject( int fingerId )
    14. {
    15.     EventSystem eventSystem = EventSystem.current;
    16.     return ( eventSystem.IsPointerOverGameObject( fingerId )
    17.         && eventSystem.currentSelectedGameObject != null );
    18. }
    19.  
     
    Last edited: Nov 19, 2014
    rakkarage likes this.
  17. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    273
    The fact that you can finally detect touches on a button, is, seriously, one of the biggest advances for Unity in years! At last! Thanks for the clarification here Bivrost, good one
     
  18. Aurecon_Unity

    Aurecon_Unity

    Joined:
    Jul 6, 2011
    Posts:
    217
    Thanks a bunch Chris, I had a setting ticked in the Event System (Allow Activation on Mobile Device) that was causing the code to not work. It's solved now and working great - appreciate your quick reply!
     
  19. mwk888

    mwk888

    Joined:
    Jan 26, 2014
    Posts:
    16
    I can't make this solution work on 4.6.0f3 Android; was there a regression? Here's my code:

    // Ignore clicks that are over UI buttons or other visible UI elements
    if (Input.touchCount > 0 && EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId)) {
    // ignore click


    but this does not work on Android because IsPointerOverGameObject() is always false. Input.touchCount and Input.GetTouch(0).fingerId all seem to be giving valid results. In fact I even tried calling IsPointerOverGameObject() for every value from -1 through 5 and the result is always false regardless of whether the click was on a UI element or not (in this case a Button).

    Has anyone got this working with the new UI on Android + 4.6.0f3?
     
    Last edited: Dec 5, 2014
    MasterChiefLegend likes this.
  20. bluescrn

    bluescrn

    Joined:
    Feb 25, 2013
    Posts:
    393
    Wouldn't it be better if we could do these tests with a simple Vector2 screen position - rather than having to know device-specific details of the touch/click?

    It looks like there's a raycast function - but it wants a PointerEventData as input, not simple coordinates - so it's clearly not intended for this use.

    Edit: Is this function returning true if the pointer is over *any* canvas object now? - I seem unable to create HUD elements that are ignored by this test, settings on Canvas Groups don't seem to change anything...
     
    Last edited: Dec 6, 2014
    mwk888 likes this.
  21. mwk888

    mwk888

    Joined:
    Jan 26, 2014
    Posts:
    16
    That certainly sounds easier. If Unity doesn't fix the Android problem quickly I may have to write that as a work around.
     
  22. mwk888

    mwk888

    Joined:
    Jan 26, 2014
    Posts:
    16
    On Windows it seems to return true over any canvas object that is drawn, so e.g. a Panel with a background returns true even if it does not interact. If your HUD has a drawn object my guess it will always be true even if parts are transparent. (Actually I kind of like this default behavior, but it would certainly be better if there was an option on Panels etc to control whether they consume UI events or not.)

    Of course on Android nothing returns true so that'd solve your problem ;D

    From an API design viewpoint, I think the real issue is IsPointerOverGameObject() seems to be a hack to make the Input full-screen APIs co-exist with the new UI. In other UI toolkits the solution for catching events that do not hit active UI elements is to have a final full screen UI element that intercepts events but does not draw at all (so it does not waste fill bandwidth even by drawing an invisible transparent layer). Then it naturally receives the events that do not hit other active UI objects. If Unity added that, and clarified the rules for how their UI event consume/propagate works (I can't figure out their docs) then IsPointerOverGameObject() would not be necessary.
     
  23. bluescrn

    bluescrn

    Joined:
    Feb 25, 2013
    Posts:
    393
    My solution to this for now is to do it the old NGUI way. Add box colliders and do a raycast myself - as this IsPointerOverGameObject is currently no use/broken.

    We need a working way to make UI elements completely ignore input, and ideally we need to be able to do manual raycasts into the UI.
     
  24. mwk888

    mwk888

    Joined:
    Jan 26, 2014
    Posts:
    16
    Here's a fix that works on both Windows and Android -- turns out it is quite easy to cast the ray manually. Two examples below, the simple one just casts from Input.mousePosition, the other lets you specify a Canvas and screen position.

    Code (CSharp):
    1. /// <summary>
    2. /// Cast a ray to test if Input.mousePosition is over any UI object in EventSystem.current. This is a replacement
    3. /// for IsPointerOverGameObject() which does not work on Android in 4.6.0f3
    4. /// </summary>
    5. private bool IsPointerOverUIObject() {
    6.     // Referencing this code for GraphicRaycaster https://gist.github.com/stramit/ead7ca1f432f3c0f181f
    7.     // the ray cast appears to require only eventData.position.
    8.     PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current);
    9.     eventDataCurrentPosition.position = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
    10.  
    11.     List<RaycastResult> results = new List<RaycastResult>();
    12.     EventSystem.current.RaycastAll(eventDataCurrentPosition, results);
    13.     return results.Count > 0;
    14. }
    15.  
    16. /// <summary>
    17. /// Cast a ray to test if screenPosition is over any UI object in canvas. This is a replacement
    18. /// for IsPointerOverGameObject() which does not work on Android in 4.6.0f3
    19. /// </summary>
    20. private bool IsPointerOverUIObject(Canvas canvas, Vector2 screenPosition) {
    21.     // Referencing this code for GraphicRaycaster https://gist.github.com/stramit/ead7ca1f432f3c0f181f
    22.     // the ray cast appears to require only eventData.position.
    23.     PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current);
    24.     eventDataCurrentPosition.position = screenPosition;
    25.  
    26.     GraphicRaycaster uiRaycaster = canvas.gameObject.GetComponent<GraphicRaycaster>();
    27.     List<RaycastResult> results = new List<RaycastResult>();
    28.     uiRaycaster.Raycast(eventDataCurrentPosition, results);
    29.     return results.Count > 0;
    30. }
    Given that works fine on Android I have no idea why IsPointerOverGameObject() is so busted
     
    jugnu, slumtrimpet, Aggressor and 5 others like this.
  25. chazzysb

    chazzysb

    Joined:
    Jan 8, 2015
    Posts:
    6
    Hi, I got around this problem by giving the UI buttons a tag, and then in code:

    If (EventSystem.current.currentSelectedGameObject != null && EventSystem.current.currentSelectedGameObject.tag == "FireButton") return;

    Hope this helps
     
    iwillbenice likes this.
  26. MasterChiefLegend

    MasterChiefLegend

    Joined:
    Jan 21, 2014
    Posts:
    2
    I've been trying to get IsPointerOverGameObject working in Unity 5 on an Android tablet, and still no success. Thanks mwk888 for useful solution! I was getting close but got in knots trying to get PointerEventData. Tested on Windows 7 and Samsung Note 10.1 running Android 4.1.2.
     
  27. Sang Cha

    Sang Cha

    Joined:
    Jul 26, 2013
    Posts:
    2
    My thanks to adhdchris and mwk888 for sharing the solution for this problem.
    It works well for iOS project as well.
     
  28. Hullabu

    Hullabu

    Joined:
    Oct 23, 2014
    Posts:
    7
    Ok, it's been a long time, but IsPointerOverGameObject still doesn't work on Android. Is Unity team going to do something with it?
     
  29. Chudziutki

    Chudziutki

    Joined:
    May 16, 2014
    Posts:
    3
    I have the same problem with IsPointerOverGameObject. In Update when any touch is down at first time always return false, but in next Update return true. So in my case i move this to LateUpdate and it works for first time always.
     
    Last edited: Aug 19, 2015
    jister likes this.
  30. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    116
    I've got a very strange problem right now with IsPointerOverGameObject, too.

    Version: Unity 5.1.1f1

    Each time I do a clean build via command line (i.e. the Library folder is recreated), when I check with IsPointerOverGameObject and the finger id while the touch phase is TouchPhase.Began, the result is false.

    When I do another build with the Library folder still in place, the version works fine and IsPointerOverGameObject returns true even in TouchPhase.Began.

    I do the check in the Update method though, not in LateUpdate. Maybe that's the problem? Anyways it should be consistent whether you make the first build or a second, third,... one.

    Does anybody else have a similar problem?
     
  31. dude4004

    dude4004

    Joined:
    Jul 15, 2014
    Posts:
    97
    Thanks, it worked like a charm!
     
    Alima-Studios likes this.
  32. Rufolangus

    Rufolangus

    Joined:
    Jan 4, 2015
    Posts:
    2
    For some reason isPointerOverGameObject always returns false. I'm running unity 4.6.6f2. We are trying to upgrade the project to 4.6.9 and will test if it works. If it does not, I have a small fix that helps in my case. Drop a rectransform covering up all of the touch area. (Our game's UI is around the sides of the screen) and RectransformUtility.RectangleContainsScreenPoint() if true, do whatever, false, don't do anything.
     
  33. Mykhaylo Hnatyuk

    Mykhaylo Hnatyuk

    Joined:
    Jul 8, 2012
    Posts:
    18
    1) You have to use fingerId

    Touch touch = Input.touches[0];
    EventSystem.current.IsPointerOverGameObject(touch.fingerId)


    2) In my case IsPointerOverGameObject returns TRUE if(touch.phase == TouchPhase.Began),
    BUT it returns FALSE if(touch.phase == TouchPhase.Ended || touch.phase == TouchPhase.Canceled)

    So you can remember if you started your touch over UI and cancel it at the end.
     
  34. KrptonCollector

    KrptonCollector

    Joined:
    May 2, 2015
    Posts:
    4
    Did anyone got it working on android
     
  35. phil-Unity

    phil-Unity

    Unity UI Lead Developer Unity Technologies

    Joined:
    Nov 23, 2012
    Posts:
    1,045
    Should work the same on android as any other platform.
     
  36. sworderzhang

    sworderzhang

    Joined:
    Jan 26, 2016
    Posts:
    2
    Not yet, I use Unity 5.2.3, IsPointerOverGameObject works different with iOS and Standalone, hence we must forget it
     
  37. jister

    jister

    Joined:
    Oct 9, 2009
    Posts:
    1,464
    seems quite normal that they would work differently on different platforms.
    mobile doesn't have a mouse for you to hover over things :)
    anyway moving the detection code to LateUpdate fixed the "only second touch got detected" problem for me.

    EDIT: nope i was lying, moving to LateUpdate didn't solve it. adding in the touch.fingerID did.
     
    Last edited: Apr 13, 2016
  38. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    273