この記事について

この記事は私がゲーム制作・学習等で学んだ知識を元に、Layout Groupの使い方をわかりやすく説明していきます。

Layout Groupを使うと、ボタンや画像を縦・横・グリッド状に自動で並べられます。まず3種類の設定を確認し、Vertical Layout Groupで縦並びのUIを作ってみましょう。この記事では、Canvasを使うUnity UI(uGUI)を扱います。

この記事でわかること

  • Horizontal・Vertical・Grid Layout Groupの使い分けと設定項目
  • Layout Elementで子のサイズを指定する方法
  • Content Size Fitterで内容に合わせて親のサイズを調整する方法
  • スクリプトでの追加・削除と、うまく並ばないときの確認点

Layout Groupとは?

Layout Groupは、取り付けたオブジェクトの直下にある子UIを自動で並べるコンポーネントです。並べたい方向に合わせて、次の3種類から選びます。

  • Horizontal Layout Group(横並び)
    子UIを横一列に配置します。メニューボタンやタブなどに使えます。
  • Vertical Layout Group(縦並び)
    子UIを縦一列に配置します。設定項目やアイテム一覧などに使えます。
  • Grid Layout Group(グリッド)
    同じサイズの子UIを格子状に配置します。アイテムスロットやステージ選択などに使えます。

Paddingで内側の余白、Spacingで子同士の間隔を指定できます。子を追加・削除したときも、レイアウトの更新時に並び直してくれます。画面サイズへの対応は、Canvas ScalerやRect Transformのアンカーも合わせて設定しましょう。

UnityのLayout Groupの使い方

Layout Groupは、並べたいUIをまとめる親に追加します。Canvasの下にPanelを作り、その子としてButtonやImageを配置するのが基本です。

Panel内の3つのボタンを縦に配置した例

CanvasやPanelの基本操作は、こちらの記事で紹介しています。

Layout Groupの種類と基本設定

Horizontal Layout Groupの追加と設定項目

  1. [Hierarchy] → [右クリック] → [UI] → [Panel]で、親となるPanelを作成します。
  2. Panelを選択し、[Add Component]から[Horizontal Layout Group]を追加します。
  3. 並べたいButtonやImageを、Panelの直下に配置します。
PanelにHorizontal Layout Groupを追加する画面

次の画像は、Horizontal Layout Groupの設定項目を確認するためのものです。後で紹介する縦並びの例では、設定値を変更します。

Horizontal Layout GroupのPaddingや子サイズの設定項目
  • Padding:親の内側に設ける上下左右の余白です。
  • Spacing:隣り合う子UIの間隔です。Horizontalでは横方向、Verticalでは縦方向に使います。
  • Child Alignment:子UIを配置した後に余白があるとき、左上・中央・右下など、どこに寄せるかを指定します。
  • Reverse Arrangement:子UIを通常と逆の順序で並べます。
  • Control Child Size:Width・Heightごとに、Layout Groupが子のサイズを制御するか指定します。ONなら子のレイアウト情報を使い、OFFならその軸のRect Transformのサイズを使います。
  • Use Child Scale:子のScaleを、サイズ計算や配置に含める設定です。WidthはScale X、HeightはScale Yに対応します。
  • Child Force Expand:余った領域を子に割り当てる設定です。子のサイズ自体も広げるには、その軸のControl Child SizeをONにします。OFFの場合は、子のサイズを変えずに配置領域へ影響します。

項目の詳細:Unity公式「Horizontal Layout Group」/共通プロパティのAPI資料。

Vertical Layout Groupの追加と設定項目

縦に並べる場合は、親Panelの[Add Component]から[Vertical Layout Group]を追加します。同じPanelにHorizontalとVerticalを両方追加する必要はありません。

PanelにVertical Layout Groupを追加する画面

画像は追加時の表示です。設定項目はHorizontal Layout Groupと共通で、縦方向の並びや行の高さを調整します。次の例では、下記の値に設定してください。

例:高さ48のImageを3つ、縦に並べる

  1. Canvas直下に新しいPanelを作り、名前をContentにします。Rect TransformのAnchor Min・Maxを両方(0.5, 1)、Pivotを(0.5, 1)、Pos Xを0、Pos Yを-20、Widthを300、Heightを200にします。
  2. ContentにVertical Layout Groupを追加します。Paddingは上下左右10、Spacingは8、Child AlignmentはUpper Leftに設定します。
  3. Control Child SizeはWidth・HeightともON、Child Force ExpandはWidthをON・HeightをOFFにします。Reverse ArrangementとUse Child ScaleはOFFにします。
  4. Contentの子に[UI] → [Image]を作り、名前をItemにします。Scaleは(1, 1, 1)のままにし、Layout Elementを追加します。Min HeightとPreferred HeightをONにして両方48、Flexible HeightをONにして0にします。
  5. Itemを複製して、Content直下に3つ並べます。PanelとItemはImageのColorを変えておくと、余白や間隔を確認しやすくなります。

この設定では、各Itemは幅280・高さ48となり、8ずつ間隔を空けて上から並びます。親の高さに余裕があっても、行の高さは引き伸ばしません。ここではContent Size Fitterをまだ追加せず、親の高さを200にしておきます。

Layout Elementは、子UIの最小・推奨・余白配分用のサイズ情報を指定するコンポーネントです。Min Heightは最小の高さ、Preferred Heightは確保したい高さ、Flexible Heightは余った高さを受け取る割合です。Preferred Heightだけでは常にその高さに固定されるとは限らないため、この例では最小値も48にそろえています。

参考:Unity公式「Vertical Layout Group」/Unity公式「Layout Element」。

Grid Layout Groupの追加と設定項目

  1. [Hierarchy] → [右クリック] → [UI] → [Panel]で、別のPanelを作成します。
  2. Panelの[Add Component]から[Grid Layout Group]を追加し、子としてButtonやImageを配置します。
PanelにGrid Layout Groupを追加する画面

次の画像で設定項目を確認します。画像のConstraintはFlexibleです。列数を固定したい場合は、この後の説明に合わせて変更してください。

Grid Layout GroupのCell SizeやConstraintの設定項目
  • Padding:グリッドの外側に設ける、親の内側の余白です。
  • Cell Size:子UI1つ分の幅と高さです。Xが幅、Yが高さになります。
  • Spacing:セル同士の横方向・縦方向の間隔です。
  • Start Corner:最初の子UIを置く角です。Upper Leftなら左上から始まります。
  • Start Axis:先に埋める方向です。Horizontalは行を横に埋めてから次の行へ、Verticalは列を縦に埋めてから次の列へ進みます。
  • Child Alignment:親の領域に余白があるとき、グリッド全体をどこに寄せるかを指定します。セル内のTextなどの位置は、その子UI側で調整します。
  • Constraint:Flexibleは行数・列数を固定しない設定、Fixed Column Countは列数を固定、Fixed Row Countは行数を固定する設定です。固定する数はConstraint Countに入力します。

Grid Layout Groupでは、子のサイズはCell Sizeで決まります。
子に付けたLayout ElementのMin・Preferred・Flexibleサイズは使用しません。Horizontal・Verticalと同じつもりでPreferred Widthを変えても、Gridのセル幅は変わらない点に注意しましょう。

3列に並べたい場合は、ConstraintをFixed Column Count、Constraint Countを3にします。アイテムが増えると行が増えますが、親自身の高さまで自動で変えたい場合は、次のContent Size Fitterも設定します。仕様:Unity公式「Grid Layout Group」。

Content Size Fitterの追加と設定項目

Content Size Fitterは、取り付けたオブジェクト自身の幅・高さを、レイアウト情報に合わせるコンポーネントです。先ほどのContentに追加すると、Vertical Layout Groupが集計したサイズ情報を使って、Content自身の大きさを調整できます。

  1. サイズを調整したい親Panel(先ほどの例ではContent)を選択します。
  2. Vertical Layout Groupが付いていることを確認し、[Add Component]から[Content Size Fitter]を追加します。
Vertical Layout Groupを付けたPanelにContent Size Fitterを追加する画面

画像は設定項目の確認用で、Horizontal Fit・Vertical FitともUnconstrainedになっています。内容に合わせて大きさを変えるには、調整したい軸を変更します。

Content Size FitterのHorizontal FitとVertical Fitの設定項目

Horizontal Fitは幅、Vertical Fitは高さを制御します。それぞれ次の3つから選びます。

  • Unconstrained:その軸のサイズをContent Size Fitterでは変更しません。
  • Min Size:その軸の最小サイズに合わせます。Horizontalなら最小幅、Verticalなら最小高さです。
  • Preferred Size:その軸の推奨サイズに合わせます。Horizontalなら推奨幅、Verticalなら推奨高さです。

参照するのは、同じGameObject上のImage・Text・Layout Group・Layout Elementなどが提供する情報です。子を並べた親にLayout GroupとContent Size Fitterを付けると、Layout Groupが子の情報を集計し、Content Size Fitterがその結果で親を調整します。仕様:Unity公式「Content Size Fitter」。

縦並びの内容に合わせて親の高さを変える

先ほどのContentでは、Horizontal FitをUnconstrained、Vertical FitをPreferred Sizeにします。幅300はそのままに、必要な高さへ調整できます。

Itemが3つなら、上下のPadding 20+高さ48×3+Spacing 8×2で、Contentの高さは180です。PivotのYを1にしてあるので、上端を基準に下方向へ伸び縮みします。

サイズを制御する役割を重複させないようにしましょう。
この例は「ContentのLayout GroupがItemのサイズを制御」「ContentのContent Size FitterがContent自身を制御」という分担です。ItemにもContent Size Fitterを付けて同じ軸を制御すると競合します。また、Content自身が別のLayout Groupの子で、その親に高さを制御されている構成でも注意が必要です。

参考:Unity公式「UIを内容のサイズに合わせる」。

Gridと組み合わせるときは行・列の制約を決める

Gridは列数によって必要な行数が変わるため、どちらの方向に伸ばすかを決めておくと設定しやすくなります。

  • 列数を固定して、縦に伸ばす:ConstraintはFixed Column Count、Vertical FitはPreferred Size。Horizontal FitをUnconstrainedにする場合は、指定した列数・Cell Size・Spacing・Paddingが収まる幅を自分で確保します。
  • 行数を固定して、横に伸ばす:ConstraintはFixed Row Count、Horizontal FitはPreferred Size。Vertical FitをUnconstrainedにする場合は、指定した行数が収まる高さを確保します。

固定側のFitもPreferred Sizeにすると、その行数・列数に必要なサイズへ合わせられます。ConstraintがFlexibleで両方のFitをPreferred Sizeにした場合は、行数と列数がほぼ同じになるよう計算されるため、特定の列数を保ちたい用途には向きません。参考:Unity公式「Grid Layout Groupと自動レイアウト」。

スクリプトでアイテムを追加・削除する

親の下にUIを生成すれば、Layout Groupが並べてくれます。先ほどの縦並びの例を使い、追加と末尾の削除を試してみましょう。

  1. 設定済みのItemをProjectウィンドウへドラッグして、Prefabにします。PrefabのGameObjectはアクティブにしておきます。
  2. LayoutGroupItems.csを作成し、次のコードを保存します。Contentの外に空のGameObjectを作り、スクリプトを追加します。
  3. InspectorのContentにはシーン内のContent、Item PrefabにはProject内のItemのPrefabを割り当てます。
  4. Contentの外に操作用Buttonを2つ作ります。ButtonのOn Click()にスクリプトを付けたGameObjectを登録し、追加用にAddItem()、削除用にRemoveLastItem()を選びます。Play中にクリックして確認します。
using UnityEngine;

public class LayoutGroupItems : MonoBehaviour
{
    [SerializeField] private RectTransform content;
    [SerializeField] private RectTransform itemPrefab;

    public void AddItem()
    {
        if (content == null || itemPrefab == null)
        {
            Debug.LogWarning("Content と Item Prefab を設定してください。", this);
            return;
        }

        Instantiate(itemPrefab, content, false);
    }

    public void RemoveLastItem()
    {
        if (content == null || content.childCount == 0)
        {
            return;
        }

        Transform item = content.GetChild(content.childCount - 1);
        item.gameObject.SetActive(false);
        item.SetParent(null, false);
        Destroy(item.gameObject);
    }
}

この例では、Content直下に追加・削除対象のItemだけを置きます。RemoveLastItem()は、Hierarchy上で最後の子を削除する処理です。

Instantiateの第2引数で親をContentに指定し、第3引数をfalseにして親を基準に生成しています。Destroyによる実際の破棄は即時ではないため、削除時は先に非表示にしてContentから外します。同じフレームで再び削除処理を呼んでも、同じ末尾の子を選び直さないためです。

Prefabの準備や親の指定は、Instantiateの使い方も参考にしてください。

参考:Unity公式 Object.Instantiate/Transform.SetParent/Object.Destroy。

うまく並ばないときの確認点

子の位置やサイズが変わらない・元に戻る

  • 親子関係:並べたいUIは、Layout Groupを付けた親の直下にありますか。Layout ElementのIgnore LayoutがONになっている子は、レイアウトの対象から外れます。
  • Horizontal・Verticalのサイズ:Control Child SizeがONの軸は、Rect Transformを直接変更する代わりにLayout ElementのMin・Preferred・Flexibleを確認します。行を伸ばしたくない場合は、Child Force ExpandのHeightと子のFlexible Heightも確認しましょう。
  • Gridのサイズ:子のRect Transformではなく、親のCell Sizeを変更します。並ぶ順番はHierarchy、Start Corner、Start Axisを確認します。

親が伸びない・子がはみ出す

縦リストならContent Size FitterのVertical Fitを確認します。さらに、親自身のサイズを別のLayout Groupやスクリプトが同じ軸で変更していないかを確認してください。GridのFixed Column Countはセルを自動で縮小する設定ではないため、親の幅が足りなければ列数・Cell Size・Spacing・Paddingを調整します。

追加・削除した直後にサイズを取得すると古い

Canvasのレイアウト計算は通常、フレーム末尾の描画前に行われます。追加・削除の直後に高さを読み取ると、まだ更新前の値の場合があります。見た目を並べ直すだけなら通常の更新に任せ、最新のサイズが必要な処理はレイアウト更新後に行いましょう。

同じフレーム内で最新の値が必要な場合は、変更後にCanvas.ForceUpdateCanvases()を呼んでから読み取る方法があります。ただし毎フレームの強制更新は避け、必要な場面だけに絞ります。LayoutRebuilder.ForceRebuildLayoutImmediateも、常時呼ぶ処理にはしないでください。参考:Unity公式「Canvas.ForceUpdateCanvases」/LayoutRebuilderの注意事項。

まとめ

  • 横一列はHorizontal、縦一列はVertical、同じサイズの格子配置はGrid Layout Groupを使います。
  • Horizontal・Verticalの子サイズはControl Child SizeとLayout Element、Gridの子サイズはCell Sizeを確認しましょう。
  • 親を内容に合わせるときはContent Size Fitterを使い、幅はHorizontal Fit、高さはVertical Fitで調整します。
  • 追加・削除は親子関係を変えればレイアウトへ反映されます。同じ軸のサイズ制御が競合しないようにし、更新タイミングにも注意しましょう。