Search Unity

  1. We are migrating the Unity Forums to Unity Discussions. On July 12, the Unity Forums will become read-only.

    Please, do not make any changes to your username or email addresses at id.unity.com during this transition time.

    It's still possible to reply to existing private message conversations during the migration, but any new replies you post will be missing after the main migration is complete. We'll do our best to migrate these messages in a follow-up step.

    On July 15, Unity Discussions will become read-only until July 18, when the new design and the migrated forum contents will go live.


    Read our full announcement for more information and let us know if you have any questions.

Feature Request Scroll Rect inertia on touch screen improve

Discussion in 'UGUI & TextMesh Pro' started by Asoprachev, Aug 15, 2022.

  1. Asoprachev

    Asoprachev

    Joined:
    Aug 13, 2017
    Posts:
    9
    A few years ago, I wrote a small fix to the standard ScrollRect, and now I found the time to contribute it. It turns out that during this time the open source repository was closed, so I will send my improvement here.

    One of the problems with all mobile Unity games is the small of scroll inertia. Open any Unity game on you smartphone and you will realize that the scrolling process causes you negative emotions. This is due to the fact that on phones, people scroll most of the content not due to the drag gesture, but due to the inertia after this gesture.

    The standard Unity's ScrollRect contains a hack to damping inertia starting velocity, and this is justified for the mouse, but disgusting for the touch. I suggest detecting if a scroll is a touch then disable the hack. This small fix makes the Unity scroll look as same as native scroll on iOS and Android and leave it the same on computers

    You should add to
    ugui/Runtime/UI/Core/ScrollRect.cs
    :
    Code (CSharp):
    1. public class ScrollRect : ... {
    2.     ...
    3.     private bool m_DraggingByTouch;
    4.     ...
    5.  
    6.     public virtual void OnBeginDrag(PointerEventData eventData) {
    7.         ...
    8.         m_DraggingByTouch = eventData.pointerId != -1;
    9.     }
    10.  
    11.     protected virtual void LateUpdate() {
    12.         ...
    13.         // replace this line: https://github.com/Unity-Technologies/uGUI/blob/5ab4c0fee7cd5b3267672d877ec4051da525913c/UnityEngine.UI/UI/Core/ScrollRect.cs#L849
    14.         m_Velocity = m_DraggingByTouch ? newVelocity : Vector3.Lerp(m_Velocity, newVelocity, deltaTime * 10);
    15.         ...
    16.     }
    17. }
    ps. I use links to an deprecated repository, but this is all relevant for the current version
    I am attaching a fully functional code for version ugui@1.0.0
     

    Attached Files:

    Last edited: Aug 15, 2022
    michael_unity145 and florius0 like this.
  2. florius0

    florius0

    Joined:
    Feb 9, 2018
    Posts:
    1
    Bump!!!!!
    Used in many projects. Makes apps feel very native.
     
    Asoprachev likes this.
  3. michael_unity145

    michael_unity145

    Joined:
    Mar 8, 2022
    Posts:
    21
    Wow feels so much better on iOS. I really wish Unity could consider implementing this.. or at least give an option for it.
     
    xucian likes this.
  4. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    860
    The built-in ScrollRect is barely production-ready in terms of UX, the performance is also (understandably) limited once you surpass a few hundred items.
     
  5. Asoprachev

    Asoprachev

    Joined:
    Aug 13, 2017
    Posts:
    9
    Yes, this is really cool, unfortunately I don’t know where to write so that the Unity team will pay attention.
    I still use this hack in all my Unity mobile projects.
    And I am triggered by terrible scrolling in many big games, but this is how you can detect their game engine)
     
  6. Asoprachev

    Asoprachev

    Joined:
    Aug 13, 2017
    Posts:
    9
    Its also true, but it many case you don't need 100+ items in scroll. Many reusable scrolls anyway use built-in ScrollRect under the hood
     
  7. nbelkin

    nbelkin

    Joined:
    Jul 22, 2012
    Posts:
    7
    You can use something like that for base ScrollRect.
    I don’t have checks to ensure that all scroll fields are set, if u need them, just modify this code.

    Code (CSharp):
    1. public class InertialScrollRect : ScrollRect
    2.     {
    3.         private bool _draggingByTouch;
    4.         private bool _isDragging;
    5.         private Vector2 _prevPosition = Vector2.zero;
    6.            
    7.         protected override void OnDestroy()
    8.         {
    9.             base.OnDestroy();
    10.                
    11.             StopAllCoroutines();
    12.         }
    13.            
    14.         public override void OnBeginDrag(PointerEventData eventData)
    15.         {
    16.             base.OnBeginDrag(eventData);
    17.                
    18.             _draggingByTouch = eventData.pointerId != -1;
    19.             _isDragging = true;
    20.         }
    21.    
    22.         public override void OnEndDrag(PointerEventData eventData)
    23.         {
    24.             base.OnEndDrag(eventData);
    25.                
    26.             _isDragging = false;
    27.         }
    28.    
    29.         protected override void OnDisable()
    30.         {
    31.             base.OnDisable();
    32.                
    33.             _isDragging = false;
    34.         }
    35.            
    36.         public override void Rebuild(CanvasUpdate executing)
    37.         {
    38.             base.Rebuild(executing);
    39.                
    40.             if (executing == CanvasUpdate.PostLayout)
    41.             {
    42.                 _prevPosition = content.anchoredPosition;
    43.             }
    44.         }
    45.    
    46.         protected override void LateUpdate()
    47.         {
    48.             base.LateUpdate();
    49.                
    50.             var deltaTime = Time.unscaledDeltaTime;
    51.             if (deltaTime > 0.0f && _isDragging && inertia)
    52.             {
    53.                 Vector3 newVelocity = (content.anchoredPosition - _prevPosition) / deltaTime;
    54.                 velocity = _draggingByTouch ? newVelocity : Vector3.Lerp(velocity, newVelocity, deltaTime * 10f);
    55.             }
    56.                
    57.             _prevPosition = content.anchoredPosition;
    58.         }
     
    xucian likes this.
  8. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    860
    ofc

    many, but not all

    this works, can I add it to the ScrollView Adapter (free asset)?
     
  9. nbelkin

    nbelkin

    Joined:
    Jul 22, 2012
    Posts:
    7
    Sure!
     
    xucian likes this.