Skip to main content

Rebuilding UI Layout from OnValidate

UI Basics and Beyond | Rebuilding UI Layout

Attempting to call LayoutRebuilder.ForceRebuildLayoutImmediate from OnValidate will result in following warning being thrown into your console: SendMessage cannot be called during Awake, CheckConsistency, or OnValidate UnityEngine.Object:Instantiate(GameObject).

We can work around this by utilizing UnityEditor.EditorApplication.delayCall (example script from Udonity):

using UdonSharp;
using UnityEngine;
using UnityEngine.UI;

namespace Varneon.VUdon.Udonity.UIElements
{
    [RequireComponent(typeof(LayoutGroup))]
    [RequireComponent(typeof(ContentSizeFitter))]
    [UdonBehaviourSyncMode(BehaviourSyncMode.None)]
    public class Foldout : UdonSharpBehaviour
    {
        public bool Expanded
        {
            get => expanded;
            set
            {
                expanded = value;

                toggle.SetExpandedStateWithoutNotify(expanded);

                SetContentExpandedState(expanded);
            }
        }

        [Header("Options")]
        [SerializeField]
        private bool expanded;

        [Header("References")]
        [SerializeField]
        private FoldoutToggle toggle;

        private void SetContentExpandedState(bool expanded)
        {
            gameObject.SetActive(expanded);

            LayoutGroup[] layoutGroups = GetComponentsInParent<LayoutGroup>(true);

            foreach (LayoutGroup layoutGroup in layoutGroups)
            {
                LayoutRebuilder.ForceRebuildLayoutImmediate(layoutGroup.GetComponent<RectTransform>());
            }
        }

#if UNITY_EDITOR && !COMPILER_UDONSHARP
        private void OnValidate()
        {
            UnityEditor.EditorApplication.delayCall += OnValidateDelayed;
        }

        private void OnValidateDelayed()
        {
            if (this == null) { return; }

            if (toggle)
            {
                toggle.Foldout = this;

                toggle.SetExpandedStateWithoutNotify(expanded);
            }

            SetContentExpandedState(expanded);
        }
#endif
    }
}