Unity UI: Vertical Layout Group を活用したインベントリ一覧UIの実装(図解付き)

本文は Unity 6(6000系)+ uGUI 2.x を前提にしています。スマホ解像度(Canvas Scaler: 1080×1920相当)を想定。

概要

インベントリのような縦リストは Vertical Layout Group を使うと配置とサイズ調整を自動化できます。要素の増減・ソート・フィルタにも強く、ScrollView と組み合わせるだけで堅牢なUIになります。


Vertical Layout Groupの基本

  • 子オブジェクトを縦方向に整列するコンポーネント。
  • Padding / Spacing / Alignment / Force Expand の4つが柱。
  • Layout Element と組み合わせることで、各カードの高さや推奨サイズを明示できます。

Inspector詳細(図解)

配置と余白の考え方

[親 (Content)] ← Padding (内側余白)
  ├─ ItemCard #1
  │
  ├─ (Spacing)
  │
  ├─ ItemCard #2
  │
  ├─ (Spacing)
  │
  └─ ItemCard #3

プロパティの意味と実戦値

区分設定役割実戦の目安
PaddingL/R/T/Bコンテナ内の余白L/R=16〜24, T/B=12〜20
Spacing数値子要素同士の間隔8〜16
Child AlignmentUpper/Middle/Lower × Left/Center/Right束全体の位置一般的に Upper Left/Center
Reverse ArrangementOn/Off並び順の反転チャット/ログ向け
Control Child SizeWidth/Height親が子のサイズを上書き幅=On, 高=On(固定高)
Use Child ScaleWidth/Height子のScale反映原則Off
Child Force ExpandWidth/Height余白の強制配分幅=On, 高=Off

注記:固定高さにする場合、各カードの Layout Element → Preferred Height を設定します(例: 100〜140)。


最小プレハブ設計図

全体構成(Hierarchy)

InventoryScroll (Prefab)
└─ Viewport (Mask)
   └─ Content  ← Vertical Layout Group + Content Size Fitter
      ├─ ItemCard (Prefab)
      ├─ ItemCard
      └─ ItemCard

Content 設定(スクショ差し込み位置)

  • RectTransform: Anchor Min/Max = (0,1)-(1,1), Pivot=(0.5,1), SizeDelta.y=0
  • Vertical Layout Group:
    • Padding: L/R=16, T=12, B=12
    • Spacing: 12
    • Child Alignment: Upper Center(または Upper Left)
    • Control Child Size: Width=On, Height=On
    • Child Force Expand: Width=On, Height=Off
  • Content Size Fitter: Horizontal=Unconstrained, Vertical=Preferred Size

スクリーンショットを挿入:Vertical Layout Group の Inspector(Content 用)

ItemCard 設計(最小)

ItemCard (Prefab)
├─ LeftIcon (optional)
└─ TextArea
   ├─ NameText (TMP)
   └─ SubText  (TMP)
  • RectTransform: Anchor=Top Stretch, Pivot=(0.5,1), SizeDelta=(0,120)
  • Layout Element: Preferred Height=120
  • NameText: FontSize=42, Overflow=Ellipsis
  • SubText: FontSize=32, Color=#666666

スクリーンショットを挿入:ItemCard の RectTransform / Layout Element / TMP 設定


実装コード(生成側・表示側)

InventoryListController(生成側)

using UnityEngine;

public class InventoryListController : MonoBehaviour
{
    [SerializeField] RectTransform content;       // Content
    [SerializeField] GameObject itemCardPrefab;   // ItemCard プレハブ

    public void AddItem(string name, int count, string note = null)
    {
        var go = Instantiate(itemCardPrefab, content);
        var card = go.GetComponent<ItemCardController>();
        card.Setup(name, count, note);
    }
}

ItemCardController(表示側)

using TMPro;
using UnityEngine;

public class ItemCardController : MonoBehaviour
{
    [SerializeField] TMP_Text nameText;
    [SerializeField] TMP_Text subText;

    public void Setup(string itemName, int count, string note = null)
    {
        if (nameText) nameText.text = itemName;
        if (subText)  subText.text  = $"x{count}" + (string.IsNullOrEmpty(note) ? "" : $"|{note}");
    }
}
ItemCard (Prefab)
├─ LeftIcon (optional)
└─ TextArea
   ├─ NameText (TMP)
   └─ SubText  (TMP)

1. LeftIcon を 置く場合

  • RectTransform: 固定サイズ (例: 100×100)
  • Anchor: 左上固定 (Min/Max=(0,1)-(0,1), Pivot=(0,1))
  • Image コンポーネントを付与(Preserve Aspect=ON)
  • TextArea の Leftマージン を +120 に設定(アイコン幅+余白ぶん)

→ アイコン付きカード(例えば食品アイテムの写真)を表示するレイアウトに。


2. LeftIcon を 置かない場合

  • LeftIcon オブジェクトを削除する、または SetActive(false) にする
  • TextArea の Leftマージンを 0 に戻す(Stretchで幅いっぱいに広げる)
  • この調整を ItemCardController の Setup() 内で分岐させると便利
public void Setup(string itemName, int count, string note = null, Sprite icon = null)
{
    if (nameText) nameText.text = itemName;
    if (subText)  subText.text  = $"x{count}" + (string.IsNullOrEmpty(note) ? "" : $"|{note}");

    if (leftIconImage)
    {
        if (icon != null)
        {
            leftIconImage.sprite = icon;
            leftIconImage.gameObject.SetActive(true);
            // TextArea の Left=120 に設定
            textArea.offsetMin = new Vector2(120, textArea.offsetMin.y);
        }
        else
        {
            leftIconImage.gameObject.SetActive(false);
            // TextArea を左詰め
            textArea.offsetMin = new Vector2(0, textArea.offsetMin.y);
        }
    }
}

3. 実運用の工夫

  • LayoutGroup を使わず、Horizontal Layout Group で LeftIcon と TextArea を横並びにすると、アイコンの有無で自動調整される(推奨)。
    • Horizontal Layout Group の設定
      • Child Force Expand: Width=OFF, Height=ON
      • LeftIcon が無ければその分スペースが縮む
  • この場合、スクリプト側で offset を切り替える必要がなくなる。

まとめ

  • LeftIconがoptional なら:
    • 簡単:スクリプトで TextArea の位置を切り替える
    • おすすめ:Horizontal Layout Group を使ってアイコン有無を自然に調整

よくあるハマり/デバッグ

  • 子の幅が伸びない:Control Child Size: Width または Child Force Expand: Width が Off。→ いずれか(多くは両方)On。
  • 高さがバラつく:各カードの Layout Element に Preferred Height がない。→ 統一値を設定。
  • スクロール範囲が合わない:Content Size Fitter(Vertical=Preferred)が不足/相互参照で無限再レイアウト。→ 親子のFitter構成を見直し。
  • 大量更新直後に崩れる:最後に1回だけ LayoutRebuilder.ForceRebuildLayoutImmediate(content)

拡張案(検索・ソート・アニメ・保存)

  • 検索/フィルタcard.gameObject.SetActive(match) 後に1回 ForceRebuild。
  • ソート:期限などで並べ替え → transform.SetSiblingIndex(i)
  • アニメ:DOTween でカード出現/削除アニメ(フェード+スケール)。
  • 保存:PlayerPrefs に JSON で保存→起動時に復元して AddItem。

まとめ

  • Vertical Layout Group はインベントリUIの定番。余白・行間・幅伸張をUI側で自動化し、実装を単純化できる。
  • 最小プレハブ(Content / ItemCard)とシンプルな2スクリプトで、運用可能な縦リストを短時間で構築できる。

付録:可変高さカードの指針

  • 固定高さ→一覧性・操作性が高い(推奨)。
  • 可変高さ→情報量は増えるが視線移動が重くなる。TextArea に Content Size Fitter(Vertical=Preferred)/親の Height 制御はOffにして干渉回避。
訪問数 3 回, 今日の訪問数 5回

UI,Unity

Posted by hidepon