【Unity UGUI 交互组件——Dropdown(TMP版本)(10)】

发布于:2025-09-13 ⋅ 阅读:(19) ⋅ 点赞:(0)

下拉菜单在游戏或者应用中都有很多应用,比如背包中的分类,语言设置等等。Unity UGUI提供了Dropdown组件来实现这个功能。参考官方手册

1.介绍

一张运行展开下拉菜单图如下,默认状态是收起状态,没有DropdownList(DropdownList运行时动态生成的​​临时性交互界面​​,它在用户点击下拉框时被创建,在选择完成后自动销毁)。
组件层级结构 。在Hierarchy 中新建 UI ▸ Dropdown-TextMeshPro 时,Unity 会自动生成 4 个必备节点:

  1. Dropdown-TextMeshPro(根节点,挂有下拉逻辑脚本 TMP_Dropdown)
  2. Label(TextMeshPro-UGUI,显示当前选中的文字)
  3. Arrow(Image,右侧小三角)
  4. Template(整个下拉列表模板,内含滚动区域、Viewport、Content 以及 Item 模板)

在这里插入图片描述

对象 中文名 作用
Dropdown (根) 下拉根节点 Dropdown 脚本
Label 标题文本 显示当前选中文字(对应 Caption Text)
Arrow 展开箭头 指示点击区域,旋转 180° 表示展开/收起
Template 列表模板 非激活,展开时克隆为下拉列表
Item (在 Template 内) 列表项模板 Toggle + Item Text / Item Image
DropdownList (展开状态下自动生成) 下拉项列表 运行时动态生成的​​临时性交互界面​​,它在用户点击下拉框时被创建,在选择完成后自动销毁。

2.组成

(1).Dropdown

在这里插入图片描述

一、Dropdown(TMP)参数

以下按在上图参数出现顺序列出常用字段,并给出用途说明。

  1. Interactable / Transition / Navigation
    与 Button、Toggle 等标准 UI 控件的交互状态完全一致,不再赘述。

  2. Template
    关联第 4 个节点 RectTransform。运行时列表展开时会把 Template 的副本实例化并显示。Template 里必须包含:
    • ScrollRect(滚动区域)
    • Content(Vertical Layout Group + Content Size Fitter,用于动态排列 Item)
    • Item(Item 模板,挂有 Toggle + Layout Element)

  3. Caption Text
    指向 Label 上的 TextMeshPro-UGUI 组件,用于显示当前选项文本。

  4. Caption Image
    如果想在文字前面再显示一个小图标(如国旗),可把 Image 拖进来,运行时会把当前选项对应的 Sprite 赋值给它。

  5. Item Text
    指向 Item 模板里的 TextMeshPro-UGUI,用于渲染列表中每一行的文字。

  6. Item Image
    同理,对应每一行的图标 Image。

  7. Value
    当前选中项的索引(int)。-1 表示未选中任何项,此时 Caption Text 会显示 Placeholder 文字。

  8. Options(List)
    在 Inspector 中可逐条添加下拉选项。每条 OptionData 包含:
    • text(string)
    • image(Sprite,可为空)

  9. Placeholder
    当 Value == -1 时,Label 会显示此占位符文字;常用于“请选择…”提示。

  10. Multi-select
    勾选后允许用户通过 Ctrl/Shift 多选;目前需自行在代码里读取 selectedIndices 数组。

  11. On Value Changed(Int32)
    标准 UnityEvent,当选中索引发生变化时触发。可拖脚本,也可运行时 AddListener。

二、常用拓展与脚本控制

  1. 动态增删选项
var dropdown = GetComponent<TMP_Dropdown>();
dropdown.options.Add(new TMP_Dropdown.OptionData("新选项"));
dropdown.RefreshShownValue();
  1. 显示/隐藏图标
dropdown.captionImage.sprite = mySprite;
dropdown.itemImage.sprite = mySprite;
  1. 监听事件
dropdown.onValueChanged.AddListener(index => Debug.Log($"选了第 {index} 项"));
  1. 样式与特效
    由于文本已替换成 TextMeshPro-UGUI,可直接在 Label/Item 上加材质参数(Outline、Shadow、Glow 等),或利用富文本标签 <sprite=0> 等实现彩色图文混排。

  2. 性能与滚动
    Template 里的 ScrollRect 拥有 Scroll Sensitivity 字段,可调整滚轮速度;若选项极多,可把 Content 上的 Vertical Layout Group + Content Size Fitter 换成更轻量的 Layout Group 或对象池方案。

(2).Laber

Label是下拉框用来显示“当前选中项文字”的专用 TextMeshPro-UGUI 节点,位于层级结构的第二层级(Dropdown-TextMeshPro ▸ Label)。它既受 TMP_Dropdown 逻辑驱动,也拥有完整的 TextMeshPro-UGUI 能力。Hierarchy 中新建 UI ▸ Dropdown-TextMeshPro 时,Unity 会同步生成 1 个 Label 节点。

在这里插入图片描述

(3).Arrow

Arrow(Dropdown-TextMeshPro 中的下拉箭头) 是位于 Caption 区域最右侧的视觉指示器,用来告诉用户“这里可以点开下拉列表”。它本质上是一个 Image 控件,挂靠在 Dropdown-TextMeshPro 的第三层级,仅做显示与过渡效果,不参与文本逻辑。细心的小伙伴可能已经看出来,这个Arrow只有RT和Image组件,并没有类似Button一样的组件,实际上他是通过射线检测的。(感兴趣点击查看原理)
在这里插入图片描述

性能这一块
• 箭头仅 1 个 Image,顶点数极低,无需对象池。
• 若使用 Addressable 图标,确保 Sprite Atlas 打包,避免额外 DrawCall。
• 在移动平台,箭头尺寸建议 ≥ 44×44 pt(苹果 HIG 最小触控区域),避免误触。

(4).Template

Template(下拉列表模板)是 Dropdown-TextMeshPro 的模板,负责在运行时把一份预先搭好的 UI 结构克隆出来,变成玩家真正能看到、能滚动的下拉列表。它平时处于 禁用状态,只有在点击下拉框时才被 实例化并激活。
在这里插入图片描述


一、它为什么会出现(设计目的)

  1. 一次性预制
    下拉列表通常包含 N 个 Item,Item 数量在运行时可能动态变化。如果把所有元素都直接放在场景里,每次增删都得实时创建/销毁,成本高。
  2. 统一样式
    通过模板,可以保证所有下拉框的外观、布局、动画完全一致,只需改一份 Template 即可全局生效。
  3. 惰性实例化
    Template 默认是 Inactive 的,不占用渲染、布局、更新开销;点击后才 Instantiate,用完 Destroy

二、Template 本身是什么

  • 一个普通的 GameObject,挂有 RectTransform。
  • 不挂载任何逻辑脚本(逻辑全部由 TMP_Dropdown 在 Show() 里接管)。
  • Scene 可见性:Inspector 里默认是灰色(未激活),运行时会被克隆为 Dropdown List(名字固定)。
  • 引用方式:TMP_Dropdown 组件的 Template 字段拖拽关联该物体;缺失会抛出 MissingReferenceException

三、Template 的标准组成(层级关系 )

Template (RectTransform)
├─ Viewport (RectTransform + Mask 或 RectMask2D + GraphicRaycaster*)
│  ├─ Content (RectTransform + Vertical Layout Group + Content Size Fitter)
│  │  ├─ Item (Toggle + Layout Element + Image + TextMeshPro-UGUI)
│  │  ├─ Item (Clone …)
│  │  └─ …
│  └─ Scrollbar (可选,Scrollbar 组件)
└─ Canvas (可选,仅当需要独立 Canvas 时)

注:带 * 的组件由 TMP_Dropdown 在运行时动态附加,模板本身不需要提前挂。


四、每个子物体的职责与关键参数

子物体 必须/可选 关键组件 & 常用设置 作用说明
Template 必须 RectTransform 模板根节点,决定整个下拉列表的锚点、尺寸;TMP_Dropdown 会把它作为克隆源。
Viewport 必须 Mask / RectMask2D + Image 把超出边缘的 Item 裁剪掉;Image 用来接收射线(点击空白处自动关闭下拉)。
Content 必须 Vertical Layout Group + Content Size Fitter 垂直排列 Item;Content Size Fitter 的 Preferred Size 让高度随 Item 数量动态增长。
Item 必须 Toggle + Layout Element 单条选项的可交互单元;Toggle 的 onValueChanged 由 TMP_Dropdown 统一接管。
└─ Item Background 内部 Image 背景图,支持不同状态(Normal / Highlighted / Pressed)。
└─ Item Checkmark 内部 Image 当前选中项的对勾图标,仅在被选中时激活。
└─ Item Label 内部 TextMeshPro-UGUI 显示文字,对应 OptionData.text。
Scrollbar 可选 Scrollbar + Image + Mask 当 Item 过多时出现;可替换成 ScrollRect 的 horizontal / verticalScrollbar

五、运行时的极简时序图

用户点击 Dropdown → TMP_Dropdown.Show()
    1. clone = Instantiate(Template)
    2. clone.name = "Dropdown List"
    3. clone.SetActive(true)
    4. clone.AddComponent<Canvas>(); clone.AddComponent<GraphicRaycaster>();
    5. 填充 Content 的子物体:根据 options.Count 复制 Item
    6. 绑定事件:点击 Item → 修改 dropdown.value → 关闭列表
用户再次点击或选择 → TMP_Dropdown.Hide()
    1. Destroy(clone)

一句话总结
Template 就是 Dropdown 的「蓝图」。

(4).Dropdown List

在这里插入图片描述

Dropdown List(运行时展开的下拉列表) 是 Template 的克隆体,在玩家点击下拉框的瞬间由 TMP_Dropdown 动态生成、填充并摆到屏幕最上层。它只在 Show() → Hide() 之间存活,生命周期极短,却是用户真正能看到、能滚动、能点选的完整 UI。


一、出现目的(为什么要克隆出它)

  1. 隔离运行时数据
    Template 只是“蓝图”——保持编辑状态不变;克隆体可随意增删 Item、改 Rect、加动画而不影响原模板。
  2. 独立渲染层级
    下拉列表需要覆盖在其他 UI 之上,因此运行时会给克隆体额外挂一个 Canvas + GraphicRaycaster,并把 sortingOrder 调高(默认 30000)。
  3. 用完即毁
    用户选中或点击外部后立刻 Destroy 避免常驻内存和更新开销。

二、Dropdown List 本身是什么

  • 名字固定:运行时实例化后统一命名为 “Dropdown List”(可在层级视图动态看到)。
  • 根节点:一个 RectTransform 组件,完全复制 Template 的锚点、尺寸、Pivot。
  • 激活开关SetActive(true) 时才可见;关闭后 SetActive(false) 或直接销毁。
  • 脚本不挂任何自定义脚本,所有逻辑仍由 TMP_Dropdown 持有并驱动。

三、标准组成(层级 & 组件)

Dropdown List (RectTransform)
├─ Viewport (RectTransform + Mask/RectMask2D + GraphicRaycaster*)
│  ├─ Content (RectTransform + Vertical Layout Group + Content Size Fitter)
│  │  ├─ Item (Toggle + Layout Element + Image + TextMeshPro-UGUI)
│  │  ├─ Item (Clone …)
│  │  └─ … (根据 options.Count 动态克隆)
│  └─ Scrollbar (Vertical) (可选)
└─ Canvas* + GraphicRaycaster*   ← 运行时由 TMP_Dropdown 自动添加

带 * 的组件在 Template 里 不存在,是运行时 额外加 的。


四、每个子物体的运行时职责 & 参数

子物体 运行时来源 关键组件 & 常用设置 作用说明
Dropdown List Instantiate(Template) RectTransform + Canvas + GraphicRaycaster 根节点;Canvas 负责独立排序,GraphicRaycaster 负责接收射线。
Viewport 克隆自 Template.Viewport Mask / RectMask2D 把超出边缘的 Item 裁剪掉;Image 背景同时作为“点击空白关闭”的检测区域。
Content 克隆自 Template.Content Vertical Layout Group + Content Size Fitter 垂直排列 Item;Content Size Fitter 的 PreferredSize 让高度随 Item 数量动态增长。
Item(N 条) 克隆自 Template.Item Toggle + Layout Element + Image + TextMeshPro-UGUI 单条可交互选项;Toggle.group 由 TMP_Dropdown 自动管理,保证单选。
└─ Item Background 克隆 Image 背景图;支持不同状态(Normal / Highlighted / Pressed)。
└─ Item Checkmark 克隆 Image 对勾图标;仅当前选中项显示。
└─ Item Label 克隆 TextMeshPro-UGUI 显示文字,自动绑定 OptionData.text。
Scrollbar 克隆自 Template.Scrollbar(可选) Scrollbar + Image + Mask 当 Item 数量超出 Viewport 高度时出现;与 ScrollRect 联动。

五、生命周期 & 关键代码片段

// TMP_Dropdown.Show() 精简流程
GameObject list = Instantiate(template.gameObject);
list.name = "Dropdown List";
list.SetActive(true);

// 1. 额外挂 Canvas 与 GraphicRaycaster
Canvas c = list.AddComponent<Canvas>();
c.overrideSorting = true;
c.sortingOrder = 30000;
list.AddComponent<GraphicRaycaster>();

// 2. 填充 Content
RectTransform content = list.transform.Find("Viewport/Content") as RectTransform;
foreach (var option in options)
{
    GameObject item = Instantiate(itemTemplate, content);
    item.GetComponentInChildren<TMP_Text>().text = option.text;
    item.GetComponent<Toggle>().onValueChanged.AddListener(OnItemValueChanged);
}

// 3. 点击空白关闭
list.GetComponentInChildren<MaskableGraphic>().AddComponent<CloseOnOutsideClick>();

总结
Dropdown List 就是 Template 的“副本”:只在需要时出生,带着独立 Canvas、排好 Item、等用户点选;任务完成立即销毁。


网站公告

今日签到

点亮在社区的每一天
去签到