How do I get a Unity Scroll Rect to scroll to the bottom after the content's Rect Transform is updated by a Content Size Fitter?
Okay, I believe I've figured it out. In most cases, Canvas.ForceUpdateCanvases();
is all you need to do before setting verticalNormalizedPosition
to zero. But in my case, the item I'm adding to the content itself also has a Vertical Layout Group component and a Content Size Fitter component. So I gotta perform these steps in this order:
Canvas.ForceUpdateCanvases();
item.GetComponent<VerticalLayoutGroup>().CalculateLayoutInputVertical() ;
item.GetComponent<ContentSizeFitter>().SetLayoutVertical() ;
scrollRect.content.GetComponent<VerticalLayoutGroup>().CalculateLayoutInputVertical() ;
scrollRect.content.GetComponent<ContentSizeFitter>().SetLayoutVertical() ;
scrollRect.verticalNormalizedPosition = 0 ;
It's a bit of a shame there's so little documentation surrounding these methods.
Proper method without Canvas.ForceUpdateCanvases and crazy iteration. Confirmed work in Unity 2018.3.12
// Assumes
ScrollRect m_ScrollRect;
And somewhere that you update ScrollRect content and want to backup scroll bar position
float backup = m_ScrollRect.verticalNormalizedPosition;
/* Content changed here */
StartCoroutine( ApplyScrollPosition( m_ScrollRect, backup ) );
And to apply new scroll position without jitter, it needs to be end of frame, we use Coroutine to wait for that timing and then use LayoutRebuilder.ForceRebuildLayoutImmediate to trigger layout rebuild only on that portion.
IEnumerator ApplyScrollPosition( ScrollRect sr, float verticalPos )
{
yield return new WaitForEndOfFrame( );
sr.verticalNormalizedPosition = verticalPos;
LayoutRebuilder.ForceRebuildLayoutImmediate( (RectTransform)sr.transform );
}
Credit to:
- https://ancientcoder.blog/2019/01/23/force-unity-to-scroll-to-the-bottom-of-a-scroll-rect/
- https://forum.unity.com/threads/scroll-rect-with-dynamic-content-reset-position-properly.518386/