Repositioning ScrollRect through code. Bug or wrong method?

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.

private ScrollRect scrollRect;
private bool ready = false;

void Awake() {
    scrollRect = GetComponent<ScrollRect>();
    if (scrollRect == null) {
        Debug.LogError("GameObject does not have a ScrollRect component. GameObject name: " + gameObject.name + " tag: " + gameObject.tag);
        Destroy(this);
    }
}

void OnEnable() {
    // if we try to access scrollRect before Start, errors are thrown (scrollRect hasn't initialised yet?)
    if (ready) {
        scrollRect.normalizedPosition = Vector2.zero;
        Debug.Log("scrollRect.normalizedPosition: " + scrollRect.normalizedPosition);
        // log prints: scrollRect.normalizedPosition: (0.5, 1.0)
    }
}

void Start() {
    ready = true;
}

Sorry if this is a duplicate post, I did do a search.

Thanks.

The top? So I guess you’re doing a vertical scroll rect? Try using scrollRect.verticalNormalizedPosition = 0;

No luck I’m afraid. Guess this must be a bug because it’s not making any sense to me.

scrollRect.verticalNormalizedPosition = 0;
Debug.Log(scrollRect.verticalNormalizedPosition); // prints 1

It says the value is 1, and yet the scroll position is about half way down.

Please file a bug with repro steps and repro project.

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 :wink:

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.

I only just submitted Case 636249.

1 Like

In case anyone is wondering, in 4.6b20, scrollRect.verticalNormalizedPosition = 0 (for bottom) and scrollRect.verticalNormalizedPosition = 1f for top does works correctly.

Same problem here. It doesn’t work here with b21.

Funny thing is, when I put the code 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?

2 Likes

Hmm, this seems like it might be related to the issue I’m having: http://forum.unity3d.com/threads/setting-scrollrect-vnormpos-in-start.276701/

I’m pretty sure it’s the same issue.
Sent a bugreport with example, case number 643604

1 Like

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:

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class RepositionScrollRectOnEnable : MonoBehaviour {
    private ScrollRect scrollRect;
    private bool ready = false;

    void Awake() {
        scrollRect = GetComponent<ScrollRect>();
        if (scrollRect == null) {
            Debug.LogError("GameObject does not have a ScrollRect component. GameObject name: " + gameObject.name + " tag: " + gameObject.tag);
            Destroy(this);
        }
    }

    void OnEnable() {
        // if we try to access scrollRect before Start, errors are thrown (scrollRect hasn't initialised yet?)
        if (ready) {
            StartCoroutine(ResetToTop());
        }
    }

    void Start() {
        ready = true;
    }

    IEnumerator ResetToTop() {
        yield return null;
        scrollRect.normalizedPosition = Vector2.one;
    }
}
4 Likes

Thanks, that did the trick! A single “yield null” Coroutine before setting the position… :eyes:

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

:rage:

Edit: above error is also avoided if you save the ScrollPosition 1 frame after generating the buttons.

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.

Thanks, Ricks!

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.

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!

“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.

1 Like

I observe same issue with 2018.3.4 - scroll view can be repositioned only by using coroutine with “yield return null”