【uGUI】ContentsSizeFitterのサイズ反映をすぐに行う方法と注意点

前提

ContentsSizeFitterは設定したコンテンツにあわせてRectTransformのサイズを調整してくれるものだが、これは即反映されない。

たとえば以下のように、テキストにContentsSizeFitterを設定し、テキストの親クラスにテキストの周りに表示する枠画像をもった状態があるとする。

そして実行時にテキストの内容を「あいうえお」→「はろーわーるど!」に変えて、枠画像のサイズもそれにあわせて調整したいとする。

using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class test_contentsSizeFitter : MonoBehaviour
{

    public Image frame;
    public TextMeshProUGUI tmp;

    void Start()
    {
        tmp.SetText("はろーわーるど!");
        frame.rectTransform.sizeDelta = tmp.rectTransform.sizeDelta + new Vector2(40, 60);
    }

}

これの実行結果は↓で意図しないものになる。

ContentsSizeFitterのサイズ反映すぐに行う

そこで、ContentSizeFitter の SetLayoutHorizontalSetLayoutVerticalを同じフレーム内で呼び出し、
即時ContentsSizeFitterのサイズ反映を行うようにする

using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class test_contentsSizeFitter : MonoBehaviour
{

    public Image frame;
    public TextMeshProUGUI tmp;

    void Start()
    {
        tmp.SetText("はろーわーるど!");

        ContentSizeFitter csf = tmp.GetComponent<ContentSizeFitter>();
        csf.SetLayoutHorizontal();        //←add!!!
        csf.SetLayoutVertical();        //←add!!!

        frame.rectTransform.sizeDelta = tmp.rectTransform.sizeDelta + new Vector2(40, 60);
    }
}

実行結果は以下になり、これで意図した対応ができた。

注意点:ContentSizeFitter をアタッチしたGameObjectがアクティブでないと働かない

非アクティブになっているGameObjectに対して同等の処理を行いたい場合には注意が必要だ。

注意が必要な状態というのは以下のどちらもあてはまる。ようはヒエラルキーでグレーアウトして非表示になっているという状態。
①ContentSizeFitterをアタッチしたGameObject自体が非アクティブの場合


②ContentSizeFitterをアタッチしたGameObjectの親が非アクティブの場合


こんなケースはないと思う人もいるかもしれないが、なくはない。
非表示のゲームオブジェクトにテキストを設定した後、後で特定のタイミングで表示するようなケースだ。

というわけで、実行時には非アクティブなテキストの内容を「あいうえお」→「はろーわーるど!」に変えて、枠画像のサイズもそれにあわせて調整。その後、ボタンを押すとテキストが表示されるという状況を作ってみる。

using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class test_contentsSizeFitter : MonoBehaviour
{
    public Button activeButton;

    public Image frame;
    public TextMeshProUGUI tmp;

    void Start()
    {
        activeButton.onClick.AddListener(() =>
        {//ボタンを押すと予め、非表示だったテキストが表示される
            this.tmp.gameObject.SetActive(true);
        });

        tmp.SetText("はろーわーるど!");

        ContentSizeFitter csf = tmp.GetComponent<ContentSizeFitter>();
        csf.SetLayoutHorizontal();
        csf.SetLayoutVertical();

        frame.rectTransform.sizeDelta = tmp.rectTransform.sizeDelta + new Vector2(40, 60);
    }

この実行結果は以下で意図した結果にならないのだ。


というわけでこれに対応するには、以下が考えられる。 ①表示したときにContentSizeFitter の SetLayoutHorizontalSetLayoutVerticalを呼ぶ ②テキスト設定時にサイズ反映するタイミングで一旦アクティブにする

②で対応しようとすると以下のようなソースになる。

using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class test_contentsSizeFitter : MonoBehaviour
{
    public Button activeButton;

    public Image frame;
    public TextMeshProUGUI tmp;

    void Start()
    {
        activeButton.onClick.AddListener(() =>
        {
            this.tmp.gameObject.SetActive(true);
        });

        tmp.SetText("はろーわーるど!");

        ContentSizeFitter csf = tmp.GetComponent<ContentSizeFitter>();
        bool active = csf.gameObject.activeInHierarchy;
        csf.gameObject.SetActive(true); //一時的にアクティブに
        csf.SetLayoutHorizontal();
        csf.SetLayoutVertical();
    if (!active)
    {
            csf.gameObject.SetActive(false); //元に戻す
    }

        frame.rectTransform.sizeDelta = tmp.rectTransform.sizeDelta + new Vector2(40, 60);
    }
}

これで意図した表示になった↓