Search Unity

Buttons within scroll rect are difficult to press on mobile

Discussion in 'UGUI & TextMesh Pro' started by nventimiglia, Aug 31, 2014.

  1. nventimiglia

    nventimiglia

    Joined:
    Sep 20, 2011
    Posts:
    153
    I have a scroll rect which presents a grid of icon buttons. On desktop the buttons are easy to click, on mobile (android) the buttons are difficult to press. When I tap them It seems that only the hover event is raised (they glow a bit) but my handlers are not invoked. If I smash my fingers into the button eventually I will raise the press event.

    Has anyone else run into this ?
     
  2. adhdchris

    adhdchris

    Joined:
    Nov 13, 2013
    Posts:
    45
    Yeah it's an issue with ScrollRect being too sensitive where even the slightest movement fires OnDrag and not OnClick. I believe Tim C said they were going to fix it in the future releases.
     
  3. morgan_heijdemann

    morgan_heijdemann

    Joined:
    May 21, 2014
    Posts:
    3
    A quick hack while waiting for the official fix is to use the PointerClick event in Event Trigger component instead of the build in OnClick() event.
     
    DominiqueT likes this.
  4. alienweb

    alienweb

    Joined:
    Mar 18, 2013
    Posts:
    11
    Yes but if we want to scroll with the finger on the button, we can't.

    Do you think is it possible to have a solution for this ?
     
  5. fertigo

    fertigo

    Joined:
    Feb 15, 2014
    Posts:
    19
    An issue has been logged for this a month ago and has the status Fixed


    Anybody here has an idea if it it will be in the next beta release and when it will come?
     
  6. adhdchris

    adhdchris

    Joined:
    Nov 13, 2013
    Posts:
    45
    This is a pretty bad solution, but a solution nonetheless. Basically have a script implement IBeginDragHandler & IEndDragHandler, measure the distance between OnBegin/OnEndDrag and fire the OnClick method if the distance is smaller than your predefined maxDistance. Something like this:
    Code (CSharp):
    1. public void OnBeginDrag (PointerEventData data)
    2.         {
    3.                 startPos = data.position;
    4.         }
    5.  
    6.         public void OnEndDrag (PointerEventData data)
    7.         {
    8.      
    9.                 float distance = Vector2.Distance (startPos, data.position);
    10.      
    11.                 if (distance < maxDistance) {
    12.                                    data.pointerPressRaycast.go.GetComponent<YourComponent>().OnClickMethod();
    13.                 }
    14.         }
    Add this to your ScrollRect object and it should do the trick.
     
    sheepgage likes this.
  7. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,225
    Fix will hopefully come very very soon. It's in the next build.
     
  8. alienweb

    alienweb

    Joined:
    Mar 18, 2013
    Posts:
    11
    With the new build (beta 19) in the scroll rect inspector, i can see Scroll Sensivity. We can change the float, but i don't know if i need to increase or decrase the number ?
     
  9. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,225
    It's the 'safe area' in screen pixels. Larger means a larger 'no drag' zone.
     
  10. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    This is not correct! Sorry Tim. :)

    Scroll Sensitivity is a multiplier for scroll-wheel / track-pad scrolling speed.

    The drag threshold feature that Tim is talking about is not included in beta 19, but we will ship a solution to this in a coming beta.

    Update: Use the Pixel Drag Threshold on the Event System component to control this.
     
    Last edited: Feb 12, 2015
    Rabadash8820, ted537, taxvi and 4 others like this.
  11. alienweb

    alienweb

    Joined:
    Mar 18, 2013
    Posts:
    11
    fixed in beta 20 thanks to unity's team !
     
  12. Kenner-Stross

    Kenner-Stross

    Joined:
    Sep 7, 2012
    Posts:
    11
    I'm still having the same problem with 4.6.1f1. Anyone else?
     
  13. Andy-Block

    Andy-Block

    Joined:
    Aug 10, 2012
    Posts:
    10
  14. zukerman

    zukerman

    Joined:
    Jan 11, 2014
    Posts:
    1
    It seems not fixed in 4.6.1f1
     
  15. iivo_k

    iivo_k

    Joined:
    Jan 28, 2013
    Posts:
    314
    Have you tried increasing the drag threshold value of the EventSystem? The default 5 is quite small.
     
  16. iivo_k

    iivo_k

    Joined:
    Jan 28, 2013
    Posts:
    314
    I noticed this myself on a full HD tablet. Not sure if there's a bug or if it's just that the default 5 px threshold is too small especially on high DPI devices. It should be a scaled value IMO.
     
    demid and runevision like this.
  17. BinaryX

    BinaryX

    Joined:
    Aug 4, 2014
    Posts:
    55
    I downloaded the ScrollRect UI component source code and modified it so i won't need the Event Trigger component on it. I introduced my code inside that new component named MyScrollRect and it worked.

    I had similar problems with this and I also had problems with OnDragEnd not being triggered from time to time, OnPointerDown on a button would break the functionality of the scroll rect and many more related to the Event Trigger.

    I'm using 4.6.1f
     
  18. princerk

    princerk

    Joined:
    Sep 30, 2014
    Posts:
    1
    Can you provide me your solution code? I am also running into this problem , don't know the solution.
     
  19. pioj

    pioj

    Joined:
    Nov 5, 2012
    Posts:
    34
    Same problem here. I'm creating this little Ogame clone for mobile and I can't scroll through my mineral topbar panel. The response is quite strange.
    BinaryX, could you upload your modified code or explain us how to fix it by ourselves, please?
     
  20. BinaryX

    BinaryX

    Joined:
    Aug 4, 2014
    Posts:
    55
    This is the modified Scroll Rect i was talking about. MyScrollRect.


    Normally, you would put a normal scroll rect component, after that add your component that has implementations for OnDrag and OnDragEnd (here, the component is HorizontalScrollSnap.cs) and then you would put an Event trigger component, add OnDrag event and link it to your component's OnDrag function.

    Something like in this example :


    Only 1 scroll rect should be enabled at a time.

    It's a hack, not a solution, but it worked for me.

    All i did was to remove the event trigger component and call my function from inside the MyScrollRect modified code.

    If you look inside MyScrollRect.cs, lines 235 and 250 are the ones you are interested in. The rest of the code is the normal Scroll Rect grabbed from the UI official source code.

    I just call the functions that needed to be called from inside the code.
    All my problems were solved by not using the Event Trigger and by doing everything manually. For example, if i wanted to know when the dragging started, i added a boolean in OnDrag like this (i didn't use OnPointerEnter, that thing wasn't behaving like it should for me).

    Code (CSharp):
    1. private bool _startDrag = true;
    2.  
    3.     public void OnDrag()
    4.     {
    5.         if (_startDrag)
    6.         {
    7.             OnDragStart();
    8.             _startDrag = false;
    9.         }
    10.     }
    And i would execute everything inside OnDragStart() function..


    The component used is Horizontal Scroll Snap component posted here on the forums. I cannot find the topic right now, but it's here somewhere. I modified it a bit to fix these problems and to support pagination bullets, buttons to browse through pages and some automated stuff. After i clean it a bit i will post it so everyone can take a look.
     

    Attached Files:

  21. SemiDemented

    SemiDemented

    Joined:
    Feb 9, 2015
    Posts:
    1
    Really looking forward to an official fix for this
     
  22. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    Like iivo_k said a month ago, please use the Pixel Drag Threshold on the Event System component to control this.
     
  23. iivo_k

    iivo_k

    Joined:
    Jan 28, 2013
    Posts:
    314
    It's a bit problematic though, while for example a 10px threshold would seem fine in the editor, it's probably way too small on a high DPI tablet. Of course it can be circumvented with a script that sets the threshold dynamically, but maybe you should consider making it a scaled or maybe physical size value.

    Edit: Canvases have a CanvasScaler by default while an EventSystem doesn't. I think the the drag threshold value should also be scaled by the possible CanvasScaler on the canvas.
     
    Last edited: Feb 13, 2015
  24. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    Yes, we talked about something like that but the Pixel Drag Threshold was added very late and we didn't have time for a more sophisticated solution at the time.

    For now you can create a script that sets the Event System Pixel Drag Threshold to be a multiple of the Scale Factor of your main Canvas:

    myEventSystem.pixelDragThreshold = 5 * myCanvas.scaleFactor;
     
    Giacas, AM-Dev and _Radagan like this.
  25. iivo_k

    iivo_k

    Joined:
    Jan 28, 2013
    Posts:
    314
    I'm now using a workaround script that allows me to set the drag threshold as a physical value in centimeters.

    Something like this (not the actual script, since there's some custom dependencies):

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.EventSystems;
    3.  
    4. /// <summary>
    5. /// Sets the drag threshold for an EventSystem as a physical size based on DPI.
    6. /// </summary>
    7. public class PhysicalDragThreshold : MonoBehaviour
    8. {
    9.     private const float inchToCm = 2.54f;
    10.  
    11.     [SerializeField]
    12.     private EventSystem eventSystem = null;
    13.  
    14.     [SerializeField]
    15.     private float dragThresholdCM = 0.5f;
    16.  
    17.     void Start()
    18.     {
    19.         if (eventSystem == null)
    20.         {
    21.             eventSystem = GetComponent<EventSystem>();
    22.         }
    23.         SetDragThreshold();
    24.     }
    25.    
    26.     private void SetDragThreshold()
    27.     {
    28.         if (eventSystem != null)
    29.         {
    30.             eventSystem.pixelDragThreshold = (int)(_dragThresholdCM * Screen.DPI / inchToCm);
    31.         }
    32.     }
    33. }
     
  26. pioj

    pioj

    Joined:
    Nov 5, 2012
    Posts:
    34
    I'm doing a similar thing in my script for setting values based on DPI, still can't get it work right as seems to not affect the build at all.

    This is so frustrating. Does anyone have a LG Nexus4 to test this tip and guide me pls?
     
  27. pioj

    pioj

    Joined:
    Nov 5, 2012
    Posts:
    34
    Is the Standalone Input Module script in the Eventsystem supposed to be (and/or checked) on a Android build? Both this and the Mobile Input Module? And their respective AllowActivationOn.. checkboxes too?

    Because I think my problem is also related to this issue...

    Any guess? thx.
     
  28. pioj

    pioj

    Joined:
    Nov 5, 2012
    Posts:
    34
    [Update]
    I've confirmed that whole problem with my UI is solved by removing/unchecking the Standalone Input script and letting just the Mobile one. As both come enabled by default when creating any UI element, I wasn't concerned at all.

    As everything works perfect now, I can continue with the game.

    If any beginner has this problem on Android phone/tablet, this seems to be the way to go.
     
    Last edited: Mar 18, 2015
  29. cradiff

    cradiff

    Joined:
    Feb 7, 2015
    Posts:
    66
    But where is Standalone Input script? Can you show here a screenshot?
     
  30. Rooney93

    Rooney93

    Joined:
    Feb 11, 2014
    Posts:
    1
    Open a scene in your project, then in the hierarchy select 'EventSystem'. In the Inspector you should see 'Standalone Input Module Script', uncheck this.
     
  31. Guillaumzed

    Guillaumzed

    Joined:
    Mar 29, 2015
    Posts:
    71
    Sadly, it's not confirmed by me...

    Situation : UI Panel containing UI Buttons -> set in a ScrollRECT
    Problem :Touch issue on mobile/android on the buttons (the buttons always flicker when they have been clicked but sometimes they launch their function, and sometimes not...) , while it always works perfectly well on my desktop.

    I unselected "Standalone input script" in the event system of the scene where the scrollRect is, then built for android, but the same problem occurs.
    Motorola G Android 5.1
     
  32. Suguma

    Suguma

    Joined:
    May 29, 2015
    Posts:
    26
    I also had a scroll rect full of buttons and couldn't have a satisfying result.
    I had the advantage that I didn't need click events for the buttons, PointerDown was already enough. So I implemented IBeginDrag, IEndDrag, IDrag and IScroll interfaces in every button and called ExecuteEvents.Execute on the scroll rect. It worked.
     
  33. Nahinho

    Nahinho

    Joined:
    Jan 21, 2014
    Posts:
    4
    Hey Guyz !

    Was watching google to find a fix to this issue. Your answers helped me, thanks for posting !
    BinaryX I downloaded your "MyScrollRect" script, added it to the gameobjects I wanted to be dragged on android devices and it doesnt worked immediately.
    I figgered why. I made the mistake to delete "ScrollRect" unity's script and replace it by the new one.
    So I added back the "ScrollRect" script in addition to the "MyScrollRect" and it worked fine !

    I'm now able to draaaaaaaag !

    Hope my share will help some of you,
    Have fun !
     
  34. magonicolas

    magonicolas

    Joined:
    Dec 4, 2013
    Posts:
    30
    I Have the Same problem, and it is supposed to be working.

    I Cant Have a Scroll Rect with Buttons, They don't click always.

    Don't Know How To Solve it, I have read all this, but when I add an event System, Scroll Rect Stops Working.

    Please help I need to make this work today!
     
    BadSeedProductions likes this.
  35. MrDasix

    MrDasix

    Joined:
    Feb 15, 2015
    Posts:
    64
    still not working :(
     
  36. enhawk

    enhawk

    Joined:
    Aug 22, 2013
    Posts:
    833
    An easy fix for this is to use Event Trigger > Pointer Up.

    For touch devices it is much more natural to implement a users decision when their finger leaves the screen, you see this in most iOS productivity apps.
     
  37. _Radagan

    _Radagan

    Joined:
    May 16, 2014
    Posts:
    38
    Thank you for this post!

    This information should be added to the Android Platform docs. Without this code change my Samsung test devices were so sensitive as to be almost unusable. I had to tweak it even further to 15 * canvas.scaleFactor for the tablet and a little higher for the phone to get the response to be what one would expect.
     
    Giacas and AM-Dev like this.
  38. Nahinho

    Nahinho

    Joined:
    Jan 21, 2014
    Posts:
    4
    Nice hack, works fine for my Alpha Tests ! Thanks.
     
  39. Johannski

    Johannski

    Joined:
    Jan 25, 2014
    Posts:
    825
    Even though that is a solution, the suggestion of @runevision is way cleaner, here is my implementation for it:

    Create the class AdaptingEventSystemDragThreshold.cs and add the script to your event system game object.
    Code (CSharp):
    1. // --------------------------------------------------------------------------------------------------------------------
    2. // <copyright file="AdaptingEventSystemDragThreshold.cs" company="Supyrb">
    3. //   Copyright (c) 2016 Supyrb. All rights reserved.
    4. // </copyright>
    5. // <author>
    6. //   Johannes Deml
    7. //   send@johannesdeml.com
    8. // </author>
    9. // --------------------------------------------------------------------------------------------------------------------
    10.  
    11. namespace Supyrb
    12. {
    13.     using UnityEngine;
    14.     using UnityEngine.EventSystems;
    15.     using System.Collections;
    16.  
    17.     public class AdaptingEventSystemDragThreshold : MonoBehaviour
    18.     {
    19.         [SerializeField] private EventSystem eventSystem;
    20.         [SerializeField] private int referenceDPI = 100;
    21.         [SerializeField] private float referencePixelDrag = 8f;
    22.         [SerializeField] private bool runOnAwake = true;
    23.  
    24.         void Awake()
    25.         {
    26.             if (runOnAwake)
    27.             {
    28.                 UpdatePixelDrag(Screen.dpi);
    29.             }
    30.         }
    31.  
    32.         public void UpdatePixelDrag(float screenDpi)
    33.         {
    34.             if (eventSystem == null)
    35.             {
    36.                 Debug.LogWarning("Trying to set pixel drag for adapting to screen dpi, " +
    37.                                "but there is no event system assigned to the script", this);
    38.             }
    39.             eventSystem.pixelDragThreshold = Mathf.RoundToInt(screenDpi/ referenceDPI*referencePixelDrag);
    40.         }
    41.  
    42.         void Reset()
    43.         {
    44.             if (eventSystem == null)
    45.             {
    46.                 eventSystem = GetComponent<EventSystem>();
    47.             }
    48.         }
    49.     }
    50. }
    Cheers,
    Johannski
     
    Menyus777, Railon23, ttesla and 8 others like this.
  40. mdrotar

    mdrotar

    Joined:
    Aug 26, 2013
    Posts:
    377
    Still no time for this? It is annoying and bug-prone to make sure everyone puts this hack-fix script in every scene.
     
    jasonMcintosh likes this.
  41. waqaswaqas

    waqaswaqas

    Joined:
    Mar 13, 2015
    Posts:
    7
    Decrease scroll sensitivity.
    Play with values.
    I mostly use 0.1 to overcome this problem.
     
    EnsenaSoft likes this.
  42. hexagonius

    hexagonius

    Joined:
    Mar 26, 2013
    Posts:
    98
    @runevision I just wanted to check by this thread to see if this still on the list or implemented in some Unity version already
     
    BadSeedProductions likes this.
  43. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    I haven't been on UI Team for a while. @phil-Unity would be one to ask instead. :)
     
    AM-Dev likes this.
  44. Skjalg

    Skjalg

    Joined:
    May 25, 2009
    Posts:
    211
    This is a bit of an issue on Android still, surprised it hasn't been looked at and fixed yet.
     
    BadSeedProductions likes this.
  45. Jet-Woods-Lim

    Jet-Woods-Lim

    Joined:
    Mar 27, 2015
    Posts:
    4
    This is my solution.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3.  
    4. [RequireComponent(typeof(Image))]
    5. public class ScrollViewButton : Button {
    6. #if !UNITY_EDITOR
    7.     public override void OnPointerClick(UnityEngine.EventSystems.PointerEventData eventData) {
    8.     }
    9.     public override void OnPointerUp(UnityEngine.EventSystems.PointerEventData eventData) {
    10.     }
    11.     public override void OnPointerExit(UnityEngine.EventSystems.PointerEventData eventData) {
    12.         base.OnPointerExit(eventData);
    13.         if (!eventData.dragging)
    14.             base.OnPointerClick(eventData);
    15.     }
    16. #endif
    17. }
     
    Finello likes this.
  46. CoopOwnz

    CoopOwnz

    Joined:
    Oct 6, 2016
    Posts:
    74
    This solution worked very well for me with hundreds of small buttons in my scroll view. Very simple to implement. Thank you for sharing. If anyone still has this issue use this.
     
    GameJob2017 and Inobinky like this.
  47. edutainment

    edutainment

    Joined:
    Dec 19, 2014
    Posts:
    16
    Thank you
    1. // <author>
    2. // Johannes Deml
    3. // send@johannesdeml.com
    4. // </author>
    and Official gonna fix this ?
     
  48. BadSeedProductions

    BadSeedProductions

    Joined:
    Dec 26, 2014
    Posts:
    144
    I raised the drag threshold in my eventsystem component, and that did the trick.
     
  49. rsofia

    rsofia

    Joined:
    Mar 24, 2016
    Posts:
    2
    Thank you! I was having the same issue. This was an easy fix and it works perfectly.
     
    GameJob2017 likes this.
  50. Finello

    Finello

    Joined:
    Feb 16, 2016
    Posts:
    2
    It works perfectly but I have add a check on the iteractable property.
    This is the code:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6. [RequireComponent(typeof(Image))]
    7. public class ButtonScroll : Button {
    8.  
    9.     #if !UNITY_EDITOR
    10.     public override void OnPointerClick(UnityEngine.EventSystems.PointerEventData eventData) {
    11.     }
    12.     public override void OnPointerUp(UnityEngine.EventSystems.PointerEventData eventData) {
    13.     }
    14.     public override void OnPointerExit(UnityEngine.EventSystems.PointerEventData eventData) {
    15.         if (this.interactable) {
    16.             base.OnPointerExit(eventData);
    17.             if (!eventData.dragging) {
    18.                 base.OnPointerClick(eventData);
    19.             }
    20.         }
    21.     }
    22.     #endif
    23. }