Search Unity

Question How to refresh ScrollView scrollbars to reflect changed content width and height?

Discussion in 'UI Toolkit' started by herra_lehtiniemi, Mar 31, 2022.

  1. herra_lehtiniemi

    herra_lehtiniemi

    Joined:
    Feb 12, 2017
    Posts:
    133
    This is the structure of my content: upload_2022-3-31_12-47-23.png
    I'm adding visualElements under the container #TimelinePillList and #TimelineChildPillList via script. However, the parent ScrollView (VerticalAndHorizontal-mode and "Infinite" scrolling) scroll bars won't reflect the new size of the the content - they simply won't update. If I click the buttons at the sides of the scroll bar, I can make it scroll to the content when in Elastic or Infinite -scroll mode, but the scroll bar width and height (the bar itself) doesn't update. Is there a way to force update the ScrollView UI, to tell it that it should check the new content width and height? It doesn't seem to do this automatically.
     
    DragonCoder likes this.
  2. AlexandreT-unity

    AlexandreT-unity

    Unity Technologies

    Joined:
    Feb 1, 2018
    Posts:
    377
    It's hard to tell without investigating the actual project. It seemed to work on my end (21.2.10f1), when I added nested VisualElements to a ScrollView. Are you using absolute positioning? If you suspect this is a bug, don't hesitate to submit a repro through the bug reporter in Help > Report a bug...
     
  3. herra_lehtiniemi

    herra_lehtiniemi

    Joined:
    Feb 12, 2017
    Posts:
    133
    Hi! Thanks for the quick reply. I query the #TimelinePillList inside the ScrollView and add elements to it. Yes, I'm using absolute positioning to add them inside the #TimelinePillList-container. Is this something that could cause the behaviour?
     
  4. AlexandreT-unity

    AlexandreT-unity

    Unity Technologies

    Joined:
    Feb 1, 2018
    Posts:
    377
    I talked with the team and it should work for both. I managed to repro in UI Builder though, with this simple UI:
    Code (CSharp):
    1.     <ui:ScrollView scroll-deceleration-rate="0,135" elasticity="0,1" style="width: 100%; height: 100%;">
    2.         <ui:VisualElement name="Outer" style="background-color: rgb(4, 255, 0);">
    3.             <ui:VisualElement name="Inner" style="width: 200px; height: 100px; background-color: rgb(0, 17, 255); position: absolute;" />
    4.         </ui:VisualElement>
    5.     </ui:ScrollView>
    6.  
    When setting the height of the nested VisualElement to 1000, the scroll bars don't immediately appear, I had to save the UXML (which forces a reload). I'll submit my repro through the bug reporter and post the case number here so you can track it.
     
  5. herra_lehtiniemi

    herra_lehtiniemi

    Joined:
    Feb 12, 2017
    Posts:
    133
    Wow, thank you so much! :) So the workaround is to adjust #unity-content-container width and height manually - this will make ScrollView bars update?
     
  6. herra_lehtiniemi

    herra_lehtiniemi

    Joined:
    Feb 12, 2017
    Posts:
    133
    Hmm, updating unity-content-container manually (via query and then unityContentContainerVisualElement.style.width = newWidth) doesn't seem to force update. Is there a way (as a workaround) - to force the scrollbar reload by script?
     
  7. herra_lehtiniemi

    herra_lehtiniemi

    Joined:
    Feb 12, 2017
    Posts:
    133
    Just for the follow-up - did you already get the case number for this? Did you happen to come up a workaround while waiting? Updating the content-container manually doesn't make the scrollbars refresh. I still haven't found a way to force them refresh.
     
  8. cpalma-unity

    cpalma-unity

    Unity Technologies

    Joined:
    Nov 30, 2020
    Posts:
    110
  9. DragonCoder

    DragonCoder

    Joined:
    Jul 3, 2015
    Posts:
    1,698
    Could perhaps the people who have run into this issue vote for the issue please? ;)
    My vote is currently the only one.

    I assume nobody has a workaround?
     
  10. DragonCoder

    DragonCoder

    Joined:
    Jul 3, 2015
    Posts:
    1,698
    Okay, found the workaround that was hinted at earlier.
    Changing the size of the scroll view does the trick, however you may not set it to the value it already has. Here I just alternate it between "99.999%" and "100%"

    Code (CSharp):
    1.  
    2.     bool scale_swap = true;
    3.     void ForceUpdateScrollViewScale()
    4.     {
    5.         var new_len = new StyleLength(UnityEngine.UIElements.Length.Percent(scale_swap ? 99.999f : 100f));
    6.         scroll_view.style.width = new_len;
    7.         scroll_view.style.height = new_len;
    8.         scale_swap = !scale_swap;
    9.     }
     
  11. littenli

    littenli

    Joined:
    Dec 18, 2019
    Posts:
    33
    I can solve this problem by using the asynchronous method of Dotween (http://dotween.demigiant.com/), which resets the height of the scroller after a delay of 0 seconds.

    Code (CSharp):
    1. float h = scroller.resolvedStyle.height;
    2.         scroller.style.height = 0;
    3.         DOVirtual.DelayedCall(0, () => {
    4.           scroller.style.height = h;
    5.         });
    But it should be solved by using Coroutine as well.
     
  12. DragonCoder

    DragonCoder

    Joined:
    Jul 3, 2015
    Posts:
    1,698
    Am seeing that this ticket has been closed with "By Design".
    Well, what is the right way to solve the problem we encountered then?

    Being able to dynamically change content of a scrollview in such a way that the scrollbars adapt feels rather fundamental to me. If not fully automated, at least provide some "EnforceRefresh" method please as the workaround is simply hacky and not reliable.
    For example on lower resolutions, the "99.999f" is too little of a difference to trigger the refresh.

    P.s. MarkDirtyRepaint does not work.


    That flickers ugly as for one frame the element is nullified. On my side since at least.
     
    Last edited: Nov 4, 2022
    UltiPangol likes this.
  13. gadoy-

    gadoy-

    Joined:
    Jul 7, 2019
    Posts:
    3
    DragonCoder likes this.
  14. AlexandreT-unity

    AlexandreT-unity

    Unity Technologies

    Joined:
    Feb 1, 2018
    Posts:
    377
    I asked @alexandred_unity, who closed the case, and he mentioned this workaround:
    Code (CSharp):
    1. void ForceUpdate(ScrollView view)
    2. {
    3.     view.schedule.Execute(() =>
    4.     {
    5.         var fakeOldRect = Rect.zero;
    6.         var fakeNewRect = view.layout;
    7.        
    8.         using var evt = GeometryChangedEvent.GetPooled(fakeOldRect, fakeNewRect);
    9.         evt.target = view.contentContainer;
    10.         view.contentContainer.SendEvent(evt);
    11.     });
    12. }
     
  15. stevphie123

    stevphie123

    Joined:
    Mar 24, 2021
    Posts:
    82
    This will happen if the ScrollView set to Wrap.. but the workaround
    @AlexandreT-unity gave, worked
     
    ZabLen likes this.
  16. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,311
    Just hit this issue as well.

    I have a tab based panel layout, where each panel contains a scrollView.
    Switch between panels removes and adds them to a parent container.
    When switching panels, the scrollView contained within doesn't update.

    You can get into a situation where you've scrolled to the bottom of one panel, switch to another that wasn't as tall, and the content is not visible, since the scrollView hasn't updated its size.

    The fix @AlexandreT-unity gave kinda works (still can get into a situation where the scrollView doesn't update). But is this seriously what we're expected to do?
    If so, why isn't this just part of the ScrollView class?

    @stevphie123 what do you mean by scrollView set to wrap?
     
    DragonCoder likes this.