Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Repositioning ScrollRect through code. Bug or wrong method?

Discussion in 'UGUI & TextMesh Pro' started by hamstar, Sep 25, 2014.

  1. hamstar

    hamstar

    Joined:
    Sep 25, 2013
    Posts:
    84
    I'm not sure why this script isn't working. Is it possible set the position of a ScrollRect in this way? I'm trying to scroll to the top on enable.

    Code (CSharp):
    1. private ScrollRect scrollRect;
    2. private bool ready = false;
    3.  
    4. void Awake() {
    5.     scrollRect = GetComponent<ScrollRect>();
    6.     if (scrollRect == null) {
    7.         Debug.LogError("GameObject does not have a ScrollRect component. GameObject name: " + gameObject.name + " tag: " + gameObject.tag);
    8.         Destroy(this);
    9.     }
    10. }
    11.  
    12. void OnEnable() {
    13.     // if we try to access scrollRect before Start, errors are thrown (scrollRect hasn't initialised yet?)
    14.     if (ready) {
    15.         scrollRect.normalizedPosition = Vector2.zero;
    16.         Debug.Log("scrollRect.normalizedPosition: " + scrollRect.normalizedPosition);
    17.         // log prints: scrollRect.normalizedPosition: (0.5, 1.0)
    18.     }
    19. }
    20.  
    21. void Start() {
    22.     ready = true;
    23. }
    Sorry if this is a duplicate post, I did do a search.

    Thanks.
     
  2. vptb

    vptb

    Joined:
    Jan 15, 2014
    Posts:
    28
    The top? So I guess you're doing a vertical scroll rect? Try using scrollRect.verticalNormalizedPosition = 0;
     
  3. hamstar

    hamstar

    Joined:
    Sep 25, 2013
    Posts:
    84
    No luck I'm afraid. Guess this must be a bug because it's not making any sense to me.
    Code (CSharp):
    1. scrollRect.verticalNormalizedPosition = 0;
    2. Debug.Log(scrollRect.verticalNormalizedPosition); // prints 1
    It says the value is 1, and yet the scroll position is about half way down.
     
  4. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    Please file a bug with repro steps and repro project.
     
  5. Drowning-Monkeys

    Drowning-Monkeys

    Joined:
    Mar 6, 2013
    Posts:
    328
    do we have any update on this? When i try this same method, it's always inconsistent, and rarely goes and stays at the top. Sometimes it starts at the top, and self-propels itself to the middle, which is where it goes by default.

    EDIT: Sorry - just noticed these posts are from today. I will wait a little longer ;-)
     
  6. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    If someone would post a case number here of the reported bug then we'd know the issue had been reported. If nobody have reported it to our bug tracker, then no amount of waiting is going to help.
     
  7. hamstar

    hamstar

    Joined:
    Sep 25, 2013
    Posts:
    84
    I only just submitted Case 636249.
     
    runevision likes this.
  8. korbain

    korbain

    Joined:
    Sep 11, 2013
    Posts:
    5
    In case anyone is wondering, in 4.6b20, scrollRect.verticalNormalizedPosition = 0 (for bottom) and scrollRect.verticalNormalizedPosition = 1f for top does works correctly.
     
  9. Ricks

    Ricks

    Joined:
    Jun 17, 2010
    Posts:
    650
    Same problem here. It doesn't work here with b21.

    Funny thing is, when I put the code
    Code (CSharp):
    1. scrollRect.normalizedPosition = new Vector2(0.0F, 1.0F);
    into the OnValueChanged method then it immediately scrolls to the top. But it doesn't scroll, until I do at least a minimal drag on the ScrollRect content. It totally ignores it if I manually try to set the value before dragging. Can someone confirm?
     
  10. authorthe

    authorthe

    Joined:
    Oct 28, 2014
    Posts:
    5
  11. Ricks

    Ricks

    Joined:
    Jun 17, 2010
    Posts:
    650
    I'm pretty sure it's the same issue.
    Sent a bugreport with example, case number 643604
     
    authorthe likes this.
  12. hamstar

    hamstar

    Joined:
    Sep 25, 2013
    Posts:
    84
    While things have improved with b21, there is still some weird behaviour. I get the feeling that the ScrollRect component, or other UI components, are modifying the scroll position in Start and/or OnEnable. So, if we try to alter the scroll position in either of these methods, the changes we make may be overwritten.

    In the end, I used a coroutine to change the scroll position on the next frame to avoid conflicting with other OnEnable/Start methods.

    Example:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using UnityEngine.UI;
    4.  
    5. public class RepositionScrollRectOnEnable : MonoBehaviour {
    6.     private ScrollRect scrollRect;
    7.     private bool ready = false;
    8.  
    9.     void Awake() {
    10.         scrollRect = GetComponent<ScrollRect>();
    11.         if (scrollRect == null) {
    12.             Debug.LogError("GameObject does not have a ScrollRect component. GameObject name: " + gameObject.name + " tag: " + gameObject.tag);
    13.             Destroy(this);
    14.         }
    15.     }
    16.  
    17.     void OnEnable() {
    18.         // if we try to access scrollRect before Start, errors are thrown (scrollRect hasn't initialised yet?)
    19.         if (ready) {
    20.             StartCoroutine(ResetToTop());
    21.         }
    22.     }
    23.  
    24.     void Start() {
    25.         ready = true;
    26.     }
    27.  
    28.     IEnumerator ResetToTop() {
    29.         yield return null;
    30.         scrollRect.normalizedPosition = Vector2.one;
    31.     }
    32. }
     
    Last edited: Oct 29, 2014
  13. Ricks

    Ricks

    Joined:
    Jun 17, 2010
    Posts:
    650
    Thanks, that did the trick! A single "yield null" Coroutine before setting the position... o_O
     
    Last edited: Oct 29, 2014
  14. Ricks

    Ricks

    Joined:
    Jun 17, 2010
    Posts:
    650
    Ok, this is f... weird:

    You want to save the current ScrollPosition via the OnValueChanged() method into PlayerPrefs?

    Well you can save it, but the ScrollRect somehow "overwrites" the values on startup like this:
    from 0.0F to 0.49999F => reloads with 0.0F
    from 0.5F to 1.0F => reloads with 1.0F

    :mad:


    Edit: above error is also avoided if you save the ScrollPosition 1 frame after generating the buttons.
     
    Last edited: Oct 30, 2014
  15. FamerJoe

    FamerJoe

    Joined:
    Dec 21, 2013
    Posts:
    193
    It's because there are issues with OnValueChanged being called more than necessary. The bug has been filed. Also with the above problem with scrolling, indeed "on the next frame" is the only way I've found of getting around it -- same goes for Scrollbars as well.
     
  16. authorthe

    authorthe

    Joined:
    Oct 28, 2014
    Posts:
    5
    Thanks, Ricks!
     
  17. authorthe

    authorthe

    Joined:
    Oct 28, 2014
    Posts:
    5
    Thanks for the example, I was looking for something that would run once without any additional ongoing overhead - looks like that's what you've achieved here.
     
  18. MikeM1970

    MikeM1970

    Joined:
    Jun 4, 2014
    Posts:
    10
    I was also having an issue with getting my Scroll Rect to scroll to the bottom immediately after appending text to the Text content inside; setting the verticalNormalizedPosition to 0f seemed to scroll the Text mostly to the bottom, but never quite all the way. The coroutine trick worked like a charm. Many thanks!
     
  19. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    476
    "It's because there are issues with OnValueChanged being called more than necessary."

    What a joke. As of Sept 2018, OnValueChanged is called every frame in most setups I've tried.

    It's just laughable.
     
    Novack likes this.
  20. dandepeched

    dandepeched

    Joined:
    Feb 22, 2016
    Posts:
    31
    I observe same issue with 2018.3.4 - scroll view can be repositioned only by using coroutine with "yield return null"
     
  21. keenanwoodall

    keenanwoodall

    Joined:
    May 30, 2014
    Posts:
    597
    It's almost 2020 and this is still a thing. Setting the value is either ignored or causes the scroll rect to propel itself randomly. I'm also seeing the issue @Ricks mentioned. I'm trying to tween the normalized position, but the tween doesn't do anything if I haven't interacted with the scroll rect in some prior to the starting of the tween.
     
    Novack likes this.
  22. Rathlord

    Rathlord

    Joined:
    Oct 13, 2013
    Posts:
    17
    @runevision is there any update to this? This issue unbelievably still exists in 2020, 6 years after the original reports and bug submissions.

    EDIT: Here's a quick and dirty workaround for Unity's sloppy implementation:

    scrollRect.velocity = new Vector2 (0f, 1000f);

    Set to -1000f if you want it to go to the top. Turn elasticity off/very low value or it'll bounce, but it works.
     
    Last edited: Jan 18, 2020
    Novack likes this.
  23. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    Case 636249 mentioned in this thread was fixed in 2014.
    Case 643604 mentioned in this thread was fixed in 2016.
    I don't see any other case numbers mentioned. If you're seeing bugs, you'll have to file bug reports, otherwise the issues can't be investigated.

    Apart from that, I haven't been part of UI team since forever, so no need to ping me specifically. @phil-Unity might be a better bet. But file those bug reports, otherwise there's little he can do either.
     
    sp-LeventeLajtai and EarthChrome like this.
  24. Lesh48

    Lesh48

    Joined:
    Dec 6, 2019
    Posts:
    1
    One of the good decisions is to assign a value in coroutine, wait until it changes, then simply assign it again. (translated)
     
  25. QuariYune

    QuariYune

    Joined:
    Jul 1, 2021
    Posts:
    20
    This bug (Or at least something similar) is still happening as of 2022 on Editor version 2022.1.20f1.

    I'm removing some objects from a content panel with both Grid Layout and content size fitter. Removing some child UI objects from the content panel and then setting verticalNormalizedPosition doesn't save the position.

    What does is calling a coroutine that waits 1 frame, and then sets the variable. This solution isn't great as it guarantees that there is a flicker in the UI when that happens. The velocity solution seems to work best as there isn't always a flicker there.