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

Unity UI Scroll Rect with dynamic content, reset position properly?

Discussion in 'UGUI & TextMesh Pro' started by bitinn, Feb 20, 2018.

  1. bitinn

    bitinn

    Joined:
    Aug 20, 2016
    Posts:
    961
    Hi,

    I am trying to get a scroll rect to behave consistently, my scenario:

    - I have this basic scroll rect setup: container (scroll rect) / viewport (mask) / content (grid layout, content size fitter, pivot and anchor at <0,1> aka top left)

    - There are a number of items in content, at runtime they are being filtered, so only some of them will be displayed, and I use SetActive to toggle each items.

    - After filtering is done, I reset Scroll Rect position to to top using verticalNormalizedPosition = 1f, but it doesn't work consistently, in some scenarios, the scroll position remain at the current scroll position.

    - This is very problematic: players should expect the scroll position to reset on each filter, but it doesn't always do that.

    I don't think it's a bug, but I wasn't able to google a clean explanation on this issue: Do I need to wait for layout rebuild to complete then reset the scroll rect position? Or was it because the elastic scroll is somehow overwriting the verticalNormalizedPosition?

    Detailed explanations and guides much appreciated!
     
  2. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    I think you can use this: https://docs.unity3d.com/ScriptReference/UI.LayoutRebuilder.ForceRebuildLayoutImmediate.html

    I'm not 100% sure, though. I'm sure I tested it before, but since I used the method below instead, I don't remember ;)

    Though, what I did & usually recommend when I see a similar post is to start a coroutine which yields until the next end of frame, and then set your normalized position there (doesn't require 1 per action, if you have more than 1 in a frame..just use a variable to keep track)
     
    bitinn likes this.
  3. bitinn

    bitinn

    Joined:
    Aug 20, 2016
    Posts:
    961
    Thx, waiting until next frame sounds like a decent solution. From the UI doc it seems layout rebuild will always be done in the same frame (or is it the next frame? I haven't checked the source code yet). Either way this approach should cover 90% of cases.

    (As for the alternative, I would probably use MarkLayoutForRebuild over ForceRebuildLayoutImmediate, as it allows Unity to manage the layout timing, so not triggering them unnecessarily; but we have only marked the element dirty, not really a callback to "reset to top when layout is done")

    Searching a bit more, I see ICanvasElement.LayoutComplete, which means I can probably implement it and listen for layout complete and then set verticalNormalizedPosition.

    Yet another approach would be to check CanvasUpdateRegistry.IsRebuildingLayout in a coroutine, pretty much the same as waiting until next frame, but perhaps safer, in case Unity somehow use multiple frames for layout rebuild.

    (I found the last suggestion in this thread, so hat-tip to user CDF)

    ----

    I will gave these solutions a go and see what's good for my case.
     
  4. chambino

    chambino

    Joined:
    Jun 4, 2018
    Posts:
    12
    Did you get it functioning? For me waiting until end of frame in a coroutine can sometime cause it to jitter for a frame because it's not necessarily called on end of every frame.