Search Unity

[Bug] Unity don't handle correctly small buttons

Discussion in 'BlackBerry' started by Wadjey, Sep 15, 2015.

  1. Wadjey


    Feb 4, 2015
    When I create a scene with small uGUI buttons (for example 40x40) and I run the app on BlackBerry device (tested with BlackBerry Q10), clicks on the buttons will not be detected by Unity, unless if I click on the top edge of the button, but if I click on the bottom edge or the middle of the button the click will not be detected.
    And this bug is causing a bad reviews for my game as the users are reporting that the buttons (to close some windows in my games for example) are not clickable :/
    The only workaround to this bug is to create a big buttons, but this will make my games ugly...
    Hopefully this bug will be resolved before the end of BlackBerry support.

    Bug case number: #727784
  2. AlexThibodeau


    Unity Technologies

    Jul 23, 2013
    We've had problems with small button sizes in the past. As I recall it was due to the high resolution that the phones run at which makes it really difficult to press buttons that are smaller than your finger tip. I unfortunately don't think I can do anything to resolve this one. What I have seen people do in the past was write their own custom buttons that react to clicks within a radius of the click itself. This allows you to be a little bit more imprecise with your tapping.
  3. Wadjey


    Feb 4, 2015
    Thanks Alex for the workaround, I'll try it.
    Please don't release Unity 5.1.4 before fixing the remaining BB10 bugs, especially the Could ID Bug.
    Last edited: Sep 19, 2015
    Jonny-Roy and MrEsquire like this.
  4. lloydsummers


    May 17, 2013
    I haven't used the Cloud ID thing, but I do all my builds locally and through BitBucket. The other bugs have all been fixed for me in 5.1.p3 and I've had some good clean builds from it.

    I rebuilt and released 4 games, and have 2 in progress using 5.1.p3 that are working great.

    I've also had my beta testers (~30) test some of the games on various models of phones including STL-001, all no issues to report.

    I will say, I am seeing the button button issue with a game with buttons at 30/40px high on 720x720 scaled as well -> scaled up on my passport, the button is bigger than my finger tip. And the button "depresses" it just doesn't always trigger the attached actions. Will read what Alex wrote and see what I can do. May try ignoring their Editor system for events and see if I can use a OnMouseUp or Touch or whatever release over the physical shape...
    Last edited: Sep 29, 2015
  5. Wadjey


    Feb 4, 2015
    If you'll find a good solution please share it with the community :)
  6. lloydsummers


    May 17, 2013
    I tried overriding the default onClick today and tackling from the script angle. Even with with button 200pixels high I'm getting intermittent activities, where the button depresses but does not execute...

    I'll keep looking tomorrow. No fix for me yet.
  7. lloydsummers


    May 17, 2013
    Haven't found a way to fix it yet.
  8. Wadjey


    Feb 4, 2015
    I hope if Unity team will find a fix and integrate it in Unity 5.1.4
  9. lloydsummers


    May 17, 2013
    I haven't had the opportunity to look into a work-around, I've been too busy with other stuff. They haven't committed or participated in this thread yet beyond Alex saying they won't look at it right now ... so I'm going to operate based on the assumption it won't be fixed by Unity.

    I'm considering throwing together a script that will poll all the events on all the uGUI objects under a canvas ... copy all the event callbacks to a reference, removing them by script, and then forcing them through a manual mouse event check of sorts ... It would be drag and drop, take some time to execute, and wouldn't deal with dynamic canvas items from prefabs. Based on my testing at this point it appears that all the Event.system stuff and uGUI editor stuff is a failed effort and operates intermittently for executing attached actions regardless of the button size (I've now replicated it on buttons sized 250x250).

    I'm personally not a fan of having to code something to replace their entire event system for canvas and undermines the purpose of uGUI but its likely the only way I'll be able to release the game I'm working on without getting stormed on the reviews. Necessary evil I suppose.

    Meanwhile, in my day job, I can't get a stable version of 5.2 that works with the webplayer either ... currently trying a fourth release. I wish they had better QA, and I'm in a bit of a tired state and starting to feel like I'm doing far too much R&D for free for them without much to show for it.. :p
    Last edited: Oct 9, 2015
  10. AlexThibodeau


    Unity Technologies

    Jul 23, 2013
    I looked into this issue a couple years ago in pretty significant depth. The crux of the issue was that the buttons were smaller than the user's finger. So what would often happen is while the start point may indeed be on the button the lifting off or finger up action was not always still on the button. You'd have to perfectly press the screen perpendicular every time so when the last part of your finger unsquished (technical term I just invented now) and leaves the screen it would still be on the button. In that particular case it would register a button click. For some reason the BlackBerry devices are extremely unforgiving when it comes to pressing small buttons.
  11. sevensails


    Aug 22, 2013
    It´s is a problem with OnClick event, onClick only works when the Tap and the "Finger Release" is inside the button.

    If you tap the button and move the finger it detects the finger is not inside the button anymore and does not execute the Click Event. This happens mainly with small buttons where your finger is bigger than the button itself, but all mobile platforms have this problem.

    Changing the OnClick event to "PointerDown" or "PointerUp" solves the problem. But it's not a easy task to change everything.

    It would be interesting to have some way to change the behavior of the default OnClick event to not requires the finger still over the button when releasing it.
  12. AlexThibodeau


    Unity Technologies

    Jul 23, 2013
    The thought did cross my mind but then assumed usage is if you press a button and decide that you really didn't want to and drag your finger off of it to release that a click wouldn't be registered. It would be a tradeoff between how users assume things work vs being super duper accurate.
  13. lloydsummers


    May 17, 2013
    The problem I'm seeing is this "isn't entirely true" to what I am experiencing. I just tested again using a very large button. Pressing and releasing while inside the touch zone but at different positions inside the touch zone - did not trigger the OnClick event.

    The button takes up 1/4 of the screen in my test, it isn't easy to miss the zone.

    That said I believe I now know why it is doing this in my case. The panel with the buttons inside it is utilizing a horizontal scroll view. When pressing and releasing with even 1 pixel difference, the touch event is moved away from the button and to the scroll view element and depressed the button without generating an event - even though you were over the button object the entire time.

    Which means, unless they press and release at the exact same pixel location, the scroll view appears to be preventing the button from receiving its OnClick. I haven't tested with a difference in the dampening, but given that the scroll view takes control on the first sign of movement, the dampening is quite unlikely to resolve the touch issue.

    Regarding the issues identified at my day job, after testing 4 versions -> I'll have to revert to Unity 5.1. The official 5.2 does not work with Visual Studio 2013 plugin (it does not integrate) for myself and 3 team members and ALL of the patch 5.2 releases generate a Webplugin build that doesn't actually execute ... sent a bug report and I'd post it on here somewhere BUT there is no platform section for webplayer. Good times.
    Last edited: Oct 9, 2015
  14. Xelnath


    Jan 31, 2015
    I am seeing this issue right now with resized buttons in Unity's Inspector gui:

    Code is roughly: = 16; = + 8f;

    then create a

    if ( GUILayout.Button("SomeText") )
    { Debug.Log("test"); }

    If you click the lower half of the button... it won't respond.
    lloydsummers likes this.
  15. BoaNeo


    Feb 21, 2013
    Unity *could* have fixed this with a configurable threshold on either the Button or the ScrollRect to determine how much scrolling would be needed to cancel a click event. 1 pixel is silly on todays super high-res mobile devices - it's actually quite difficult to hold your finger that still.

    I ended up fixing this in a custom Button class. It's not difficult, just annoying - I've hooked into all the drag events, and check when the touch has moved more than my allowed threshold. Once beyond the threshold, all events are passed directly to the ScrollRect and PointerUp is ignored. Seems to work so far :)

    (BNEventTrigger is just a helper class derived from EventTrigger - you can achieve the same by deriving directly from EventTrigger, though you will then expose EventTrigger functionality in the inspector, which probably isn't what you want).

    I have not included any of the animation code since I don't need it, should be simple enough to add.

    If you have a lot of Buttons you need to port, you can do what I did and add the [ExecuteInEditor] tag and put it some code to grab the needed settings from the existing Button instance.

    Code (CSharp):
    2. public class BNButton : MonoBehaviour
    3.   {
    4.     public float _dragToScrollThreshold = 10;
    5.     public float _maxScrollToCancel = 5;
    6.     public UnityEvent _onClick;
    8.     bool _down;
    10.     bool _pass;
    12.     bool _scrolled;
    14.     Vector2 _positionAtDown;
    16.     Vector3 _scrollStart;
    18.     Image _image;
    20.     public Image image
    21.     {
    22.       get
    23.       {
    24.         if(_image==null)
    25.         {
    26.           _image = GetComponent<Image>();
    27.         }
    28.         return _image;
    29.       }
    30.     }
    32.     void Awake()
    33.     {
    34.       BNEventTrigger trigger = BNEventTrigger.CreateFor( gameObject );
    36.       trigger.onPointerDown = (PointerEventData eventData) =>
    37.       {
    38.         _scrolled = false;
    39.         _pass = false;
    40.         _down = true;
    41.         _positionAtDown = eventData.position;
    42.         eventData.Use();
    43.       };
    44.       trigger.onInitializePotentialDrag += (PointerEventData eventData) =>
    45.       {
    46.         PassToScrollRect(eventData, (ScrollRect rect) => { rect.OnInitializePotentialDrag( eventData ); });
    47.       };
    48.       trigger.onBeginDrag += (PointerEventData eventData) =>
    49.       {
    50.         PassToScrollRect(eventData, (ScrollRect rect) => { rect.OnBeginDrag( eventData ); });
    51.       };
    52.       trigger.onEndDrag += (PointerEventData eventData) =>
    53.       {
    54.         PassToScrollRect(eventData, (ScrollRect rect) => { rect.OnEndDrag( eventData );  });
    55.       };
    56.       trigger.onDrag += (PointerEventData eventData) =>
    57.       {
    58.         PassToScrollRect(eventData, (ScrollRect rect) => { rect.OnDrag(eventData); });
    59.       };
    60.       trigger.onPointerUp = (PointerEventData eventData) =>
    61.       {
    62.         if(_down && !_scrolled)
    63.         {
    64.           Vector3[] corners = new Vector3[4];
    65.           ((RectTransform)transform).GetWorldCorners( corners );
    67.           if(corners[0].x<eventData.position.x && corners[2].x>eventData.position.x && corners[0].y<eventData.position.y && corners[1].y>eventData.position.y)
    68.             _onClick.Invoke();
    69.         }
    70.         _down = false;
    71.       };
    72.     }
    74.     void PassToScrollRect(PointerEventData eventData, Action<ScrollRect> pass)
    75.     {
    76.       float moved = (eventData.position - _positionAtDown).magnitude;
    77.       if(_pass || moved > _dragToScrollThreshold )
    78.       {
    79.         eventData.Use();
    80.         ScrollRect rect = GetComponentInParent<ScrollRect>();
    81.         if(rect!=null)
    82.         {
    83.           if(!_pass)
    84.             _scrollStart = rect.content.position;
    85.           _pass = true;
    86.           pass(rect);
    87.           if((_scrollStart-rect.content.position).magnitude>_maxScrollToCancel)
    88.             _scrolled = true;
    89.         }
    90.       }
    91.     }
    92.   }