TL;DR
子にContentSizeFitterを設定したときは、親のLayoutGroupのControlChildSizeをオフにすること。
動機
「Textコンポーネントを使って動的に大きさが変化するUI」(行の増えていくログ機能など)を作りたかった。
しかし、自身のUIサイズを調整するContentSizeFitterを使うとUnityEditorで警告がでて無効になったり、ContentSizeFitterを使わないと求める機能が実現できなかったりした。
公式ドキュメント(自動レイアウト - Unity マニュアル)を読んでもよくわからず...
こちらを見たところやっと理解できたので、やりたかったことに必要な原理の理解と設定方法をまとめた。
uGUIの自動レイアウトを根っこのほうから理解する|fuqunaga|note
原理:uGUIのレイアウト処理
uGUIの自動レイアウトを根っこのほうから理解する|fuqunaga|note より抜粋・要約
uGUIの2種類のレイアウト処理方法
処理の流れ 処理 通常のレイアウト 親 -> 子 親の矩形(RectTransform)をもとに子の矩形が一意に決まる。 自動レイアウト 親 <- 子 子の情報をもとに自分自身や子のRectTransformを編集する。 自動レイアウトの例)「Text コンポーネントなど内容によってサイズが変わるUIがはみ出さないように親のUIのサイズを広げる」など
自動レイアウト
自動レイアウトは以下の2つの要素から成る。
LayoutElement: 自身のサイズについての「要望」
- 要望なのでこれ単体では特になにも変化しない
- LayoutElementとして扱われるのは ILayoutElement を継承するコンポーネント全て
- つまり、 LayoutElement コンポーネント だけでなく、Text や Image もLayoutElementとして自身のサイズの要望を伝える。
LayoutController: RectTransform の編集者
- 「要望」を元に(自身or子の)RectTransformを編集する。
- 複数のレイアウトコントローラーの編集が衝突しないように Editor 上でのサポートがある。
- (つまり、複数LayoutControllerで1つのRectTransformを編集してはいけない)
- 主なLayoutControllerの挙動
- ContentSizeFitter: 自身のサイズをレイアウトエレメントの Min または Preferred にする。
- LayoutGroup: Control Child Size が OFF のときは(子の)サイズの変更はなく位置だけ整列する。
「Textコンポーネントを使って動的に大きさが変化するUI」の設定例
GameObjectのヒエラルキー
各GameObjectの設定値
- TextContainerのVerticalLayoutGroupは、ControlChildSizeをOFFにする。
- つまり、子(text)のサイズを編集しない。
- Text11はTextとContentSizeFitterを設定。
- つまり、Textコンポーネントのサイズ要望を、自身のContentSizeFitterで設定する。
※VerticalLayoutGroupは、両方のインターフェースを実装してるので、両方の役割を持つ
まとめ
子にContentSizeFitterを設定したときは、親のLayoutGroupのControlChildSizeをオフにすること。
複数のLayoutControllerが同時にRectTransformのSizeを編集しないようにするため。
備考:ILayoutElement/ILayoutControllerの実装
公式ドキュメント(Unity - Scripting API: LayoutGroup など)を見て、厳密にはILayoutElement/ILayoutControllerがどのように実装されているか、クラス図をおこして確認した。
自動レイアウト周りの実装のクラス図
VerticalLayoutGroupは、(LayoutGroup, HorizontalOrVerticalLayoutGroupを経由して)ILayoutElement/ILayoutControllerの両方を実装しているのが分かる。
ButtonはLayoutGroup・LayoutElementどちらでもない。
PUMLコード
@startuml
interface ILayoutController
interface ILayoutElement
interface ILayoutGroup
' interface ILayoutSelfController
ILayoutController <|.. LayoutGroup
ILayoutElement <|.. LayoutGroup
ILayoutGroup <|.. LayoutGroup
LayoutGroup <|-- HorizontalOrVerticalLayoutGroup
HorizontalOrVerticalLayoutGroup <|-- VerticalLayoutGroup
HorizontalOrVerticalLayoutGroup <|-- HorizontalLayoutGroup
' ILayoutSelfController <|.. ContentSizeFitter
ILayoutController <|.. ContentSizeFitter
ILayoutElement <|.. LayoutElement
ILayoutElement <|.. Text
ILayoutElement <|.. Image
Selectable <|-- Button
@enduml