Could anyone kindly guide, how to use UI Rect Scroll for a content that might grown dynamically by adding content after a web service call or with respect to some button response by the user in game interface.
Following the tutorial available on Unity website, it show how to scroll an image which is greater in size than the scroll rect, but how to get this setup working for stuffs that might be added to the panel later in game or runtime, which will increase in height or width but still the scroll will reflect to the old height or width, rather than the new dimensions.
I spent a lot of time to solve this issue. I tried every proposed solution on the web. None of them gave me the result i needed. I ended up calculating the height via a Script (MonoBehavior).
My aim was to calculate a 2D RectTransform (ScrollContent) that has children populated dynamically using the start() so the script executes once on update() after all has been initialized.
I added this to all the component with dynamic height and the scroll content.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ScrollExpander : MonoBehaviour {
private bool _updated = false;
// Use this for initialization
void Update () {
if (!_updated) {
RectTransform rectTransform = (RectTransform)transform;
float yMin = 0.0f;
float yMax = 0.0f;
foreach (RectTransform child in transform) {
yMin = Mathf.Min (yMin, child.offsetMin.y);
yMax = Mathf.Max (yMax, child.offsetMax.y);
}
float finalSize = yMax - yMin;
rectTransform.sizeDelta = new Vector2 (rectTransform.sizeDelta.x, finalSize);
_updated = true;
}
}
}
Think you need to add Component Content SizeFilter and set it to unrestrained
EDIT:
Well that’s what I get for not checking my own menu item. BoredMormon is right you have to set the RectTransform to dynamically increase in size with enough for each item that you include.
In my case that’s just vertical but it could be both.
See RectTransform.OffSetMax and RectTransform.OffSetMin
get the count of how many items are being loaded and multiply that by the how many times you’re going to increase the x and y.
Not written the code to fix mine yet but if you’re struggling I’ll post the solution when I have it.
To create a dynamic list of objects I use Horisontal/Vertical Layout Group in combination with Aspect Ratio component.
In this case, I can on the fly change the screen orientation, resolution or add/remove elements - but interface will behave predictable anyway.
Create a prefab of a list item and attach Aspect Ratio component, so that the object held their aspect.
Create panel object - full list container. And attach two component:
a. Horisontal/Vertical Layout Group - this component will put items in order
b. Aspect Ratio - the component we’ll be changing through code, depending on the items count and their personal aspect ratio
(like - containerAspectRatio = itemAspectRation * (float) itemArray.Count; )
After setting the content height, you also need to handle the scroll position. If you want to keep the % vertical scroll position the same, a solution is below. Add the script as component to the scene. Assign the scrollRect variable by drag and drop in editor. In your managing script, declare the scroll position class:
public ScrollRectVerticalPositionHolderOnContentHeightChange scrollHolder;
Then assign the script in editor by drag and drop. Whenever you update the content height of Scroll Rect, call the method ContentHeightUpdated()
using UnityEngine;
using System;
using UnityEngine.UI;
using System.Collections;
public class ScrollRectVerticalPositionHolderOnContentHeightChange: MonoBehaviour {
public ScrollRect scrollRect;
float lastVerticalScrollPosition;
void Start() {
scrollRect.onValueChanged.AddListener(TableScrolledEvent);
}
void TableScrolledEvent(Vector2 value)
{
lastVerticalScrollPosition = scrollRect.verticalNormalizedPosition;
}
public void ContentHeightUpdated() {
StartCoroutine(SetVerticalPositionScroll());
}
IEnumerator SetVerticalPositionScroll()
{
// If you set the orderscontent port, the scroll position resets. To avoid this, the position is set in the frame after a change in content port height
yield return 0;
scrollRect.verticalNormalizedPosition = lastVerticalScrollPosition;
}
}
it states it’s called by the layout system, but seems like working me even if i call it manually to update the layout after modifications to it’s content.