hyonarge
hyonarge

Reputation: 33

How to get Prefab size before Instantiating?

I have a Prefab made of an Image element and a Text element in the Image. Depending on the length of the text, the prefab gets wider or taller. In script, I need to change the text and get the new size (height, width) of the prefab BEFORE using Instantiate(prefab). My problem is that I'm always getting a size of 0, or the size of the original prefab, without the text modification. My script looks like that :

prefab.GetComponent<Text>().text = myNewText; //insert a long text, supposed to make the prefab wider
float newSize = prefab.GetComponent<Image>().preferredWidth // always getting 0 or the original width of the prefab

// do some things with newSize

Instantiate(prefab);

PS : There is no Collider or mesh renderer in my prefab.

I also tried .GetComponent<RectTransform>().sizeDelta or .GetComponent<RectTransform>().rect.size.y but I always get 0 or the size of the original prefab, without the longer text.

Upvotes: 0

Views: 2138

Answers (2)

derHugo
derHugo

Reputation: 90659

The thing is that you will have to wait until the UI has done a refresh so all layout groups etc are up-to-date.

By default

A canvas performs its layout and content generation calculations at the end of a frame, just before rendering, in order to ensure that it's based on all the latest changes that may have happened during that frame.

If you do not want to wait a frame what you will need to use is Canvas.ForceUpdateCanvases

var newInstance = Instantiate(prefab); 
newInstance.GetComponent<Text>().text = myNewText;

Canvas.ForceUpdateCanvases();
Debug.Log(newInstance.GetComponent<Text>().preferredWidth);

This can of course be expensive though depending on the complexity and amount of Canvases you have.


If you rather want to wait a frame you would need to use a coroutine and do

    StartCoroutine(SpawnRoutine());

...

private IEnuemrator SpawnRoutine()
{
    var newInstance = Instantiate(prefab); 
    newInstance.GetComponent<Text>().text = myNewText;

    yield return new WaitForEndOfFrame();

    Debug.Log(newInstance.GetComponent<Text>().preferredWidth);
}

Upvotes: 1

Kitsomo
Kitsomo

Reputation: 133

My solution to this would be: Instantiate the prefab, Set it as inactive in the scene, get the size, modify it as you like, then set it active again. It should look something like this

Gameobject newPrefab = Instantiate(prefab);
newPrefab.SetActive(false);
float newSize = newPrefab.GetComponent<Image>().preferredWidth;
DoStuff();
newPrefab.SetActive(true);

Have not tested this, but I think this is why you are not getting a width before instantiating

Upvotes: 1

Related Questions