Unity 6 × TextMeshPro TMP_Dropdownの使い方・実践ガイド

TL;DR

  • 必須:using TMPro; を入れて TMP_Dropdown を使う(UnityEngine.UI.Dropdown とは別物)。
  • オプションは AddOptions(List<string>) / AddOptions(List<TMP_Dropdown.OptionData>)。更新後は必要に応じて RefreshShownValue()。
  • 初期値をコードで変えるときは SetValueWithoutNotify(int) を使うと onValueChanged を発火させない。
  • 現在の表示テキストは dropdown.options[dropdown.value].text で取得。
  • 典型レシピ:Enumバインド親子ドロップダウンアイコン付き項目PlayerPrefsで永続化ローカライズ対応

対象と前提

  • Unity 6(UGUI)+ TextMeshPro(TMP)
  • Canvas / EventSystem がシーンに存在していること
  • 新規 UI は TextMeshPro 系を採用(旧 Dropdown と混在させない)

なぜ TMP_Dropdown?

  • 高品質な文字表示(日本語でも崩れにくい)
  • リッチなテンプレート(スクロール、アイコン、チェックマーク等)
  • OptionData(text, image) による 画像付き項目 の標準サポート

まずは1分で動く最小サンプル

1) ヒエラルキーに追加

Create > UI > TextMeshPro > Dropdown を追加(自動で Canvas, EventSystem も用意されます)。

2) スクリプト

using UnityEngine;
using TMPro;

public class LocationDropdown : MonoBehaviour
{
    [SerializeField] private TMP_Dropdown dropdown;
    // 例:「冷蔵 / 冷凍 / 常温」
    private static readonly string[] Options = { "冷蔵", "冷凍", "常温" };

    private const string PrefKey = "LocationDropdown.Value";

    private void Awake()
    {
        // 参照の取り違い防止
        if (!dropdown) dropdown = GetComponent<TMP_Dropdown>();

        dropdown.ClearOptions();
        dropdown.AddOptions(new System.Collections.Generic.List<string>(Options));

        // 保存値を復元(なければ0)
        var saved = PlayerPrefs.GetInt(PrefKey, 0);
        dropdown.SetValueWithoutNotify(Mathf.Clamp(saved, 0, Options.Length - 1));
        dropdown.RefreshShownValue(); // 表示更新

        // 変更イベント
        dropdown.onValueChanged.AddListener(OnValueChanged);
    }

    private void OnDestroy()
    {
        dropdown.onValueChanged.RemoveListener(OnValueChanged);
    }

    private void OnValueChanged(int index)
    {
        var label = dropdown.options[index].text;
        Debug.Log($"選択: {index} - {label}");
        PlayerPrefs.SetInt(PrefKey, index);
    }
}

ポイント

  • ClearOptions() → AddOptions(…) の順で初期化。
  • 復元時は SetValueWithoutNotify でイベントループを回避。
  • 最後に RefreshShownValue() で表示テキストを更新。

オプションの入れ方いろいろ

1) 文字列のリストで追加

dropdown.AddOptions(new List<string> { "Easy", "Normal", "Hard" });

2) 画像付き(OptionData)

var list = new List<TMP_Dropdown.OptionData>
{
    new TMP_Dropdown.OptionData("剣", swordSprite),
    new TMP_Dropdown.OptionData("弓", bowSprite),
    new TMP_Dropdown.OptionData("杖", staffSprite),
};
dropdown.AddOptions(list);

Note: Template(子階層の Template/Viewport/Content/Item)に Image が配置されていれば、項目の画像が表示されます。編集時に一時的に Template を有効化 して見た目を調整し、無効化状態に戻して保存 するのがコツ。


値変更イベントの取り扱い

インスペクターで結びたい派

  • On Value Changed (Int) に受け取り側メソッド(public void OnChanged(int i))をドラッグ&ドロップ。

スクリプトで結びたい派

dropdown.onValueChanged.AddListener(i =>
{
    var selected = dropdown.options[i].text;
    // TODO: 適用処理
});

初期値をコードでセットする時の落とし穴

  • dropdown.value = n; は onValueChanged が発火
  • 発火させたくない 場合は SetValueWithoutNotify(n) を使う。

便利レシピ集

A. Enum をそのままバインド

public enum Quality { Low, Medium, High, Ultra }

[SerializeField] TMP_Dropdown qualityDropdown;

void Start()
{
    var names = System.Enum.GetNames(typeof(Quality));
    qualityDropdown.ClearOptions();
    qualityDropdown.AddOptions(new List<string>(names));

    qualityDropdown.onValueChanged.AddListener(i =>
    {
        var q = (Quality)i;
        ApplyQuality(q);
    });
}

B. 親子ドロップダウン(カテゴリー → サブカテゴリー)

[SerializeField] TMP_Dropdown parentDD;
[SerializeField] TMP_Dropdown childDD;

readonly Dictionary<string, string[]> Map = new()
{
    { "飲料", new[] { "水", "お茶", "コーヒー" } },
    { "食品", new[] { "パン", "米", "麺" } },
};

void Awake()
{
    parentDD.ClearOptions();
    parentDD.AddOptions(new List<string>(Map.Keys));

    parentDD.onValueChanged.AddListener(_ => RebuildChild());
    RebuildChild();
}

void RebuildChild()
{
    var key = parentDD.options[parentDD.value].text;
    childDD.ClearOptions();
    childDD.AddOptions(new List<string>(Map[key]));
    childDD.SetValueWithoutNotify(0);
    childDD.RefreshShownValue();
}

C. アイコン付きメニュー

  • Template/Item 内に Image(アイコン領域)と TMP_Text(ラベル)を配置。
  • 上の 画像付き OptionData を使って AddOptions。

D. PlayerPrefs で永続化(共通化ユーティリティ)

public static class DropdownPrefs
{
    public static void BindWithPrefs(TMP_Dropdown dd, string key, int defaultIndex = 0)
    {
        var saved = PlayerPrefs.GetInt(key, defaultIndex);
        dd.SetValueWithoutNotify(Mathf.Clamp(saved, 0, dd.options.Count - 1));
        dd.RefreshShownValue();
        dd.onValueChanged.AddListener(i => PlayerPrefs.SetInt(key, i));
    }
}

E. ローカライズ(ランタイムで差し替え)

void ApplyLocale(Dictionary<string, string> table)
{
    // 例:キーは内部ID、値が翻訳済みテキスト
    for (int i = 0; i < dropdown.options.Count; i++)
    {
        var id = dropdown.options[i].text;         // 内部IDとして流用
        if (table.TryGetValue(id, out var localized))
        {
            dropdown.options[i].text = localized;  // 置き換え
        }
    }
    dropdown.RefreshShownValue();
}

見た目と操作性の整え方

  • Template を編集:Viewport/Content/Item のレイアウト、Toggle の Background/Checkmark、Label のフォントサイズ/余白を調整。
  • フォーカス/ナビゲーション:Selectable の Navigation を「自動」→「明示」にすると、キーボードやコントローラ操作の経路を制御できる。
  • スクロール:項目が多い場合は ScrollRect の設定を確認(Content の Vertical Layout Group と Content Size Fitter の整合性)。

トラブルシュート(よくあるつまずき)

  1. Dropdown と TMP_Dropdown を混同→ TextMeshPro を使うなら TMP_Dropdown を選ぶ。スクリプトも using TMPro;。
  2. ドラッグ&ドロップで参照が入らない→ 参照先が TMP_InputField / TMP_Dropdown か確認。旧 InputField / Dropdown と型が異なると入らない。
  3. 変更が表示に反映されない→ オプションを書き換えた後は RefreshShownValue()。
  4. 勝手に onValueChanged が走る→ 初期化や復元では SetValueWithoutNotify() を使う。
  5. テンプレートを編集したら開かなくなった
  • Template の構造(Viewport/Content/Item)や Toggle の参照を壊していないか。
  • 編集時に Template を有効化 → 保存前に 無効化 へ戻す。
  1. スクロールできない/マスクされない→ Viewport に Mask or RectMask2D、ScrollRect の Content/Viewport の紐付け確認。

すぐ使えるスニペット集

現在の選択テキストを取得

string label = dropdown.options[dropdown.value].text;

全オプション差し替え

dropdown.ClearOptions();
dropdown.AddOptions(new List<string>(new[] { "A", "B", "C" }));
dropdown.SetValueWithoutNotify(0);
dropdown.RefreshShownValue();

文字列からインデックスを探して選択

int FindIndexByText(TMP_Dropdown dd, string text)
{
    return dd.options.FindIndex(o => o.text == text);
}
// 使用例
var idx = FindIndexByText(dropdown, "常温");
if (idx >= 0) dropdown.SetValueWithoutNotify(idx);

チェックリスト

  • using TMPro; を入れた
  • TMP_Dropdown を使っている(旧 Dropdown ではない)
  • Canvas と EventSystem あり
  • 初期化は ClearOptions() → AddOptions()
  • 復元/初期セットは SetValueWithoutNotify()
  • オプション変更後は RefreshShownValue()
  • Template 構造と ScrollRect の紐付け良好

インスペクターから登録するには

1) UI の TMP_Dropdown コンポーネントに直接登録(最も手軽)

  1. オブジェクトを選択 → Inspector の TMP_Dropdown を開く
  2. Options セクションで + を押して項目を追加
    • 各項目に Text(表示名)と Image(任意のSprite)を設定
  3. Value で初期選択を指定
  4. 画像を使う場合は、Template/Viewport/Content/Item に Image と TMP_Text があることを確認
    • 編集時は Template を一時的に有効化してレイアウト調整し、保存前に無効化に戻すのがコツ
  5. 使い回すなら Prefab 化

注意:スクリプト側の参照型は TMP_Dropdown を使ってください(UnityEngine.UI.Dropdown とは別物)。型が違うとドラッグ&ドロップで参照が入りません。


2) スクリプトで「インスペクタ編集 → 実行時に反映」

インスペクタで項目リストだけ編集し、起動時にまとめて反映する方法です。

(多言語・動的差し替え・親子ドロップダウンなどに発展しやすい)

using System.Collections.Generic;
using UnityEngine;
using TMPro;

public class DropdownBinder : MonoBehaviour
{
    [SerializeField] TMP_Dropdown dropdown;         // ヒエラルキーから割り当て
    [SerializeField] List<string> options;          // インスペクタで編集
    [SerializeField] int defaultIndex = 0;          // 既定の選択

    void Awake()
    {
        if (!dropdown) dropdown = GetComponent<TMP_Dropdown>();

        dropdown.ClearOptions();
        dropdown.AddOptions(options);
        dropdown.SetValueWithoutNotify(Mathf.Clamp(defaultIndex, 0, options.Count - 1));
        dropdown.RefreshShownValue();
    }
}

アイコン付きにしたい場合は List<TMP_Dropdown.OptionData> をシリアライズして同様に AddOptions します(Template に Image が必要)。


補足:スクリプトのフィールド自体をインスペクタでプルダウン表示したい?

  • 組み込みでプルダウンになるのは enum 型です。
  • 任意の文字列リストをそのままプルダウンにする標準属性はありません。必要なら CustomPropertyDrawer / Editor 拡張(または外部アセット)で実装します。

訪問数 2 回, 今日の訪問数 2回

UI,Unity

Posted by hidepon