Search Unity

How to have smooth scrolling for scroll bars?

Discussion in 'UGUI & TextMesh Pro' started by cxode, Jun 11, 2019.

  1. cxode

    cxode

    Joined:
    Jun 7, 2017
    Posts:
    268
    When I use my mouse's scroll wheel to scroll in a scroll rect, the scroll bar instantly jumps to the next position. I would like it to smoothly move to the next position, in the same way most desktop web browsers work. How can I do this?
     
    Tymianek and PutridEx like this.
  2. cxode

    cxode

    Joined:
    Jun 7, 2017
    Posts:
    268
    Bump. Over a year later and I'm still trying to figure out how to do this. Found my own thread while searching the forums lol.
     
  3. Havie

    Havie

    Joined:
    Oct 12, 2019
    Posts:
    89
    Hey man, I just started messing with scrollable areas in Unity,

    what I have is a gameobject with a mask component and scroll rect as the parent
    then a child that is a container that holds all the items that extend beyond the size of the area.

    on the parents scroll rect there is a setting for scroll sensitivity and a few other things like clamped vs elastic. Never seen it do whar you described.
    The scroll bar itself which you can add as a child has a setting for number of steps. maybe that does something
     
  4. cxode

    cxode

    Joined:
    Jun 7, 2017
    Posts:
    268
    Woo, I finally figured it out!! This has been on the feature wishlist for my game since 2018, I am so stoked to have finally got it working.

    The method I am using is to create a new class which inherits from
    ScrollRect
    and override the
    OnScroll
    method. You then intercept the scroll event, and smooth the value over multiple frames.

    Here's a basic implementation using the DoTween library:

    Code (CSharp):
    1. using DG.Tweening;
    2. using UnityEngine;
    3. using UnityEngine.EventSystems;
    4. using UnityEngine.UI;
    5.  
    6. /// <summary>
    7. /// Version of <see cref="ScrollRect"/> that supports smooth scrolling.
    8. /// </summary>
    9. public class SmoothScrollRect : ScrollRect
    10. {
    11.     public bool SmoothScrolling { get; set; } = true;
    12.     public float SmoothScrollTime { get; set; } = 0.08f;
    13.  
    14.     public override void OnScroll(PointerEventData data)
    15.     {
    16.         if (!IsActive())
    17.             return;
    18.  
    19.  
    20.         if (SmoothScrolling)
    21.         {
    22.             Vector2 positionBefore = normalizedPosition;
    23.             this.DOKill(complete: true);
    24.             base.OnScroll(data);
    25.             Vector2 positionAfter = normalizedPosition;
    26.  
    27.             normalizedPosition = positionBefore;
    28.             this.DONormalizedPos(positionAfter, SmoothScrollTime);
    29.         }
    30.         else
    31.         {
    32.             base.OnScroll(data);
    33.         }
    34.     }
    35. }
    36.  
    Unfortunately you can't display the properties (
    SmoothScrolling
    and
    SmoothScrollTime
    ) in the inspector by default, as
    ScrollRect
    has a custom inspector drawer. If you want to draw those properties you'll have to add a class that inherits from ScrollRectEditor.

    Hope this helps somebody!
     
    Last edited: Oct 24, 2020
  5. adamgolden

    adamgolden

    Joined:
    Jun 17, 2019
    Posts:
    1,555
    It hadn't occurred to me I could just subclass a built-in inspector the same way as a normal class. That tip alone was worth a thank you. Not sure why I didn't think to try that before.. opens up some quality of life improvements.

    Do you happen to know how to view/figure out the class name of the current custom inspector being used for a given component in the Inspector? That would also be helpful.. if there's a way ?
     
    andreiagmu and cxode like this.
  6. cxode

    cxode

    Joined:
    Jun 7, 2017
    Posts:
    268
    Cheers!

    Custom inspectors use the
    CustomEditor
    attribute. For example, if you open up
    ScrollRectEditor.cs
    , one of the first lines is
    [CustomEditor(typeof(ScrollRect), true)]
    So you should be able to search the code for
    [CustomEditor(typeof(the type you want to find the inspector for)]
    .
     
    andreiagmu and adamgolden like this.
  7. adamgolden

    adamgolden

    Joined:
    Jun 17, 2019
    Posts:
    1,555
    Genius! Thanks! :D
     
    andreiagmu and cxode like this.
  8. petemanzel

    petemanzel

    Joined:
    Dec 30, 2017
    Posts:
    6
    Hi, i am pretty new to Unity and have only a very basic understanding of programming but i really would like to make my horizontally scrolling box scroll smoother. I installed the dotween library. How can i implement your code to my UI "scroll view". Thanks for any help!
     
  9. cxode

    cxode

    Joined:
    Jun 7, 2017
    Posts:
    268
    You have to create a new class/file, and paste the code above into it. That adds a new type of scroll rect that you can use instead of the vanilla Unity ones.
     
  10. petemanzel

    petemanzel

    Joined:
    Dec 30, 2017
    Posts:
    6
    Thank you for your reply. I don`t get it. If i ad the script to the "scroll view" where the "scroll rect" is located i get that error you see in the screenshot

    P.S: Happy Eastern.
     

    Attached Files:

    • test.png
      test.png
      File size:
      66.8 KB
      Views:
      515
  11. cxode

    cxode

    Joined:
    Jun 7, 2017
    Posts:
    268
    Happy Easter indeed :)

    I suspect the issue is that you named the file
    smoothscroll
    while the name of the class is
    SmoothScrollRect
    . Unity requires that monobehaviors have the same file name as the class name.

    Aside from that, the inspector is telling you that there might be compile errors on the script. Are there? You would see them as errors in the console if so.

    Also keep in mind that once you've added the SmoothScrollRect, you will have to remove the original ScrollRect component for it to work properly.
     
    petemanzel likes this.
  12. petemanzel

    petemanzel

    Joined:
    Dec 30, 2017
    Posts:
    6
    THANK YOU! It works and is fantastic! I increased the SmoothScrollTime to 0.5f and it behaves exactly like i imagined it.
     
    cxode likes this.
  13. petemanzel

    petemanzel

    Joined:
    Dec 30, 2017
    Posts:
    6
    One more question, if possible. How can i limit the function of scrolling only to the mouse scrollwheel and not to the touch gesture of swiping?
     
  14. cxode

    cxode

    Joined:
    Jun 7, 2017
    Posts:
    268
    I don't think the base Unity scroll rect supports turning that off, and my quick skim of the documentation suggests I'm correct. You can probably disable it by making your custom scroll rect override the OnBeginDrag, OnDrag and OnEndDrag functions with empty methods.
     
    erdostamasa likes this.
  15. Venturex

    Venturex

    Joined:
    Jun 22, 2018
    Posts:
    1
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5. using UnityEngine.EventSystems;
    6.  
    7. public class PreventDragging : MonoBehaviour, IBeginDragHandler, IEndDragHandler
    8. {
    9.     public void OnBeginDrag(PointerEventData eventData)
    10.     {
    11.         GetComponent<ScrollRect>().StopMovement();
    12.         GetComponent<ScrollRect>().enabled = false;
    13.     }
    14.     public void OnEndDrag(PointerEventData eventData)
    15.     {
    16.         GetComponent<ScrollRect>().enabled = true;
    17.     }
    18. }
    19.  
    Just put that script on the gameobject where the scrollrect component is on
     
    cxode likes this.
  16. Galaxy227

    Galaxy227

    Joined:
    Apr 3, 2022
    Posts:
    5
    Hey cxode, I went ahead and copied your code into a script for smooth scrolling (as I can't find anything online).

    I can no longer scroll with the mouse wheel? For the sake of troubleshooting, I've even got two objects, one with Unity's default ScrollRect, and the other with your SmoothScrollRect script, and am setting each of their values to be the same in the inspector. Only Unity's script works with the mouse wheel, whereas yours does not.

    What gives? There are no compiler errors, and I can still drag & drop with SmoothScrollRect. Just no mouse wheel movement.
     
  17. cxode

    cxode

    Joined:
    Jun 7, 2017
    Posts:
    268
    I have no idea, sorry. It's very hard for me to guess what's wrong with your setup, since the only information you've provided is "it doesn't work". I encourage you to attempt to debug the code and figure out which part of it isn't being triggered correctly.
     
  18. Nikita_Gedjua

    Nikita_Gedjua

    Joined:
    Nov 2, 2021
    Posts:
    1
    If someone also does not scroll like @Galaxy227, check if you forgot to insert Content and Viewport into the fields upload_2022-11-18_14-9-57.png