Search Unity

ScrollRect verticalNormalizedPosition doesn't work properly

Discussion in 'UGUI & TextMesh Pro' started by papirosnik, Mar 29, 2015.

  1. papirosnik

    papirosnik

    Joined:
    Feb 17, 2012
    Posts:
    6
    HI everyone.
    I have 'ScrollView' object with ScrollRect component on it and its child's 'Content' object (and vertical ScrollBar too).
    The 'Content' gameobject also has VerticalLayoutGroup and ContentSizeFitter components in order to order child items properly.
    In OnEnable method I destroy all children of the 'Content' element and create new ones from the scratch.
    Last lines in that method are:
    ...
    ScrollRect sr = _content.parent.GetComponent<ScrollRect>();
    sr.verticalNormalizedPosition = 1.0f;
    }

    But ScrollRect always point me on the last added item when it is first time shown, i.e. it scrolls to the bottom of the content. Btw, I use its Elastic and Inertia properties...

    The only soulution I manged to get this working is the following:
    ...
    StartCoroutine(locateFirst());
    }

    void locateFirst()
    {

    yield return new WaitForSeconds(0.5f);
    ScrollRect sr = _content.parent.GetComponent<ScrollRect>();
    sr.verticalNormalizedPosition = 1.0f;
    }
    It works, although has its own drawback... Namely, when my ui is shown first time I see the last child's element during short time and then (after 0.5 s.) content jumps to the first childs element. It is not very good.
    I can reduce the paramter for the WaitForSeconds() method even to 0.15f and it still works (and time gap before 'jumping' is decresed too) but that bad visual mash (jumping from the last element to the first one) still exists. 0.1 s. already doesn't do this job - the last element still is shown.

    It seems that the ScrollRect scrolls its content internally during some short time after the content is programatically changed.
    And we need to select that time parameter empirically because it looks irrelevant to the Deceleration Rate property of the ScrollRect.

    I supposed that ScrollRect uses its Inertia and/or Elastic properties for this. I tried to disable those properties but this didn't help me.
    Also I tried to use scrollRect.StopMovement()... no success.
    Also I tried to set immediately anchoredPosition for the 'Content' gameobject... no sucess.
    Also I tried to set value property of the linked ScrollBar.... no sucess.

    Again, the only solution is wait until ScrollRect ends up its 'inteernal' scrolling.
    Then verticalNormalizedPosition is able to do its work.

    So, my questions are:
    How to locate content of ScrollRect object at desired position immediately after that content is changed (suppose in OnEnable method)?
    What do ScrollRect.StopMovement really do and why it doens't work for 'internal' scrolling?
    Why programmatically changed value of the linked ScrollBar(-s) doesn't affect on the ScrollRect content position?
     
  2. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,290
    Anyone ever solved this?
     
  3. Mese

    Mese

    Joined:
    Dec 13, 2015
    Posts:
    41
    I'm Having this problem too... Anyone knows how to solve it?
    Thanks!
     
  4. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    Add these variables to your Script:
    Code (CSharp):
    1. bool scrollToTop;
    2. ScrollBar vScroll;
    In Start get a handle on the Vertical ScrollBar
    Code (CSharp):
    1. vScroll = SomeGetCompoentCall();  //Not sure how your UI is setup
    Set scrollToTop to true when you create new Content, or whenever you'd like the ScrollRect to be at the top

    Create a function called whatever you like:
    Code (CSharp):
    1. public void HandleScrollToTop()
    2. {
    3.          if (scrollToTop)
    4.          {
    5.                   scrollToTop = false;
    6.                   vScroll.value = 1;
    7.           }
    8. }
    Then In your Editor Navigate to the Vertical ScrollBar. Go down to On Value Changed. Click + and Link it to HandleScrollToTop

    If after created new Content this doesn't work because its setting the value to 1 then a Content Size Fitter or some other thing is changing the scrollBar value you can try this:
    Add this after you add new Content:
    Code (CSharp):
    1. //Create new Content Here
    2. vScroll.value = .34526
    3. StartCoroutine(WaitForScrollChange)
    4.  
    5. IEnumerate WaitForScrollChange()
    6. {
    7.        bool flag = true;
    8.        while (flag)
    9.         {
    10.                 yield return null;
    11.                 if (vScroll.value != .34526)
    12.                          flag = false;
    13.         }
    14.         scrollToTop = true;
    15. }