LayoutGroup
は便利ですが、公式にも重いため最適化するためには利用は避けようと記述されています
Some of the best optimization tips for Unity UI - Unity
理由としては上記リンクに書いている通りですがどういった処理をしているのか見ていきます
OnRectTransformDimensionsChange
で Rect の変更を検知して
Root の LayoutGroup であればダーティフラグを立てます
※ 他にも ダーティフラグを立てる処理はあります
Root かどうか判定する際に parent の GetComponent を行います
// LayoutGroup protected override void OnRectTransformDimensionsChange() { base.OnRectTransformDimensionsChange(); if (isRootLayoutGroup) SetDirty(); } private bool isRootLayoutGroup { get { Transform parent = transform.parent; if (parent == null) return true; return transform.parent.GetComponent(typeof(ILayoutGroup)) == null; } }
その後 LayoutRebuilder
で UI の再構築処理が呼ばれ、そのときに自分の子供にいる LayoutGroup
一覧を取得します
//LayoutRebuilder private void PerformLayoutControl(RectTransform rect, UnityAction<Component> action) { if (rect == null) return; var components = ListPool<Component>.Get(); rect.GetComponents(typeof(ILayoutController), components); ・ ・ ・ for (int i = 0; i < rect.childCount; i++) PerformLayoutControl(rect.GetChild(i) as RectTransform, action); ・ ・ ・ private void PerformLayoutCalculation(RectTransform rect, UnityAction<Component> action) { if (rect == null) return; var components = ListPool<Component>.Get(); rect.GetComponents(typeof(ILayoutElement), components); ・ ・ ・ for (int i = 0; i < rect.childCount; i++) PerformLayoutControl(rect.GetChild(i) as RectTransform, action);
その後また LayoutGroup
側で 無視する UI かどうかを判定するために ILayoutIgnorer を取得しています
// LayoutGroup public virtual void CalculateLayoutInputHorizontal() { m_RectChildren.Clear(); var toIgnoreList = ListPool<Component>.Get(); for (int i = 0; i < rectTransform.childCount; i++) { var rect = rectTransform.GetChild(i) as RectTransform; if (rect == null || !rect.gameObject.activeInHierarchy) continue; rect.GetComponents(typeof(ILayoutIgnorer), toIgnoreList);
まだ他にも GetComponent は呼ばれていますが、UIの再構築のためにこれだけの GetComponent が呼ばれています
そのため要素の数が多ほど 重くなってしまいます
最適化したいのであれば公式に書いてあるとおり自前でレイアウトを構築する処理を必要があります
解決法:可能な限り Layout Group を避ける
プロポーショナルレイアウトを設計するときは、アンカーを使用します。なお、要素数が動的に変化する UI に関しては、 レイアウトを計算する独自のコードを記述し、すべての変更に対してそのコードは使わず、オンデマンドでのみ使用するようにしてください。