【Unity UGUI】Toggle / ToggleGroup 与 Dropdown

张开发
2026/4/20 10:21:16 15 分钟阅读

分享文章

【Unity UGUI】Toggle / ToggleGroup 与 Dropdown
文章目录0. 效果预览1. 需求分析2. Hierarchy 搭建Toggle 层级结构ToggleGroup 用法Dropdown 层级结构3. 核心组件配置Toggle 组件参数ToggleGroup 组件参数TMP_Dropdown 组件参数4. 完整代码4.1 Toggle 事件监听4.2 ToggleGroup 单选获取选中项4.3 Dropdown 基础用法与动态填充4.4 Dropdown 带图标选项5. 使用方法Toggle 开关ToggleGroup 单选Dropdown 下拉列表6. 参数说明Toggle 脚本参数ToggleGroup 脚本参数Dropdown 脚本参数7. 变体与扩展7.1 Toggle 自定义样式图标替换7.2 Dropdown 搜索过滤7.3 多级联动 Dropdown8. 常见问题9. 性能 / 适配建议0. 效果预览Toggle 和 Dropdown 是 UGUI 中最常用的选择类组件Toggle 做开关/单选/多选Dropdown 做下拉列表。看似简单但 ToggleGroup 的互斥逻辑、Dropdown 的动态填充、自定义样式这些细节不搞清楚就容易踩坑。1. 需求分析核心思路Toggle 一个可切换的 bool 状态 视觉反馈勾选图标ToggleGroup 让多个 Toggle 互斥Dropdown 一个可展开的选项列表 选中回调。典型使用场景设置界面的开关音效开/关、推送开/关难度选择简单/普通/困难单选互斥装备筛选标签多选武器、防具、饰品语言切换下拉列表分辨率 / 画质选择角色职业选择需要实现的功能点Toggle 基础用法与事件回调ToggleGroup 互斥逻辑单选模式Toggle 多选模式不加 GroupToggle 自定义样式替换勾选图标Dropdown 基础用法与选项填充Dropdown 动态添加/删除选项代码控制Dropdown 自定义样式TMP_Dropdown 对比前置知识建议先阅读本系列 文章 1总领篇了解 Canvas、RectTransform、EventSystem 的基本概念。2. Hierarchy 搭建Toggle 层级结构Canvas └── Toggle ← Toggle 组件 Layout Element可选 ├── BackgroundImage ← 未选中时的背景框 │ └── CheckmarkImage ← 选中时显示的勾选图标 └── LabelText / TMP_Text ← 文字标签可选Toggle父对象挂Toggle组件。Graphic属性指向 BackgroundTarget Graphic控制交互高亮Background未选中状态的视觉通常是一个方框/圆框Checkmark选中状态的视觉勾号/填充色/图标Toggle 组件会自动控制它的gameObject.SetActiveLabel文字说明非必须ToggleGroup 用法在父对象上挂ToggleGroup组件然后把每个 Toggle 的Group属性拖拽指向这个 ToggleGroup。同一 Group 内的 Toggle 自动互斥——选中一个其他自动取消。Canvas └── DifficultyPanel └── ToggleGroup 组件挂在 Panel 上 ├── Toggle_Easy ← Group 指向 DifficultyPanel ├── Toggle_Normal ← Group 指向 DifficultyPanel └── Toggle_Hard ← Group 指向 DifficultyPanelDropdown 层级结构Canvas └── Dropdown (TMP) ← TMP_Dropdown 组件 Image背景 ├── LabelTMP_Text ← 当前选中项的显示文字 ├── ArrowImage ← 下拉箭头图标 └── TemplateScrollRect ← 下拉列表模板默认隐藏 └── ViewportMask └── Content └── ItemToggle ← 单个选项的模板 ├── Item BackgroundImage ├── Item CheckmarkImage └── Item LabelTMP_TextDropdown父对象挂TMP_Dropdown或原生Dropdown组件Template下拉列表的模板平时SetActive(false)隐藏点击时克隆并显示Item单个选项的模板Dropdown 会根据选项数量克隆多份3. 核心组件配置Toggle 组件参数参数说明Is On初始选中状态true/falseToggle Transition切换动画None无/ Fade淡入淡出Graphic选中时显示的图形通常指向 CheckmarkGroup所属的 ToggleGroup不设 独立 Toggle可多选On Value Changed状态变化时的回调事件参数为 boolToggleGroup 组件参数参数说明Allow Switch Off是否允许全部取消选中。false 必须有一个选中单选模式true 可以全不选关键Allow Switch Off false时用户点击已选中的 Toggle 不会取消它——必须点另一个才能切换。这是单选按钮的标准行为。TMP_Dropdown 组件参数参数说明Options选项列表可在 Inspector 中手动添加也可代码动态填充Value当前选中项的索引从 0 开始Caption Text指向显示当前选中项文字的 TMP_TextCaption Image指向显示当前选中项图标的 Image可选Item Text指向选项模板中的 TMP_TextItem Image指向选项模板中的 Image可选Template指向下拉列表模板的 RectTransformOn Value Changed选中项变化时的回调事件参数为 int 索引4. 完整代码4.1 Toggle 事件监听usingUnityEngine;usingUnityEngine.UI;/// summary/// Toggle 基础事件监听示例/// 挂载到任意对象Inspector 中拖入对应的 Toggle 引用/// /summarypublicclassToggleExample:MonoBehaviour{[SerializeField]privateToggle_soundToggle;[SerializeField]privateToggle_musicToggle;voidStart(){// 监听 Toggle 状态变化 _soundToggle.onValueChanged.AddListener(OnSoundToggleChanged);_musicToggle.onValueChanged.AddListener(OnMusicToggleChanged);}privatevoidOnSoundToggleChanged(boolisOn){Debug.Log($音效:{(isOn?开:关)});// AudioManager.Instance.SetSoundEnabled(isOn);}privatevoidOnMusicToggleChanged(boolisOn){Debug.Log($音乐:{(isOn?开:关)});// AudioManager.Instance.SetMusicEnabled(isOn);}voidOnDestroy(){// 移除监听防止内存泄漏 _soundToggle.onValueChanged.RemoveListener(OnSoundToggleChanged);_musicToggle.onValueChanged.RemoveListener(OnMusicToggleChanged);}}4.2 ToggleGroup 单选获取选中项usingUnityEngine;usingUnityEngine.UI;usingSystem.Linq;/// summary/// ToggleGroup 单选模式获取当前选中的 Toggle/// /summarypublicclassToggleGroupExample:MonoBehaviour{[SerializeField]privateToggleGroup_difficultyGroup;/// summary/// 获取当前选中的 Toggle按钮点击时调用/// /summarypublicvoidOnConfirmDifficulty(){// 获取 Group 中当前选中的 Toggle // ActiveToggles() 返回所有 isOntrue 的 ToggleToggleactiveToggle_difficultyGroup.ActiveToggles().FirstOrDefault();if(activeToggle!null){Debug.Log($选中难度:{activeToggle.name});}}/// summary/// 也可以给每个 Toggle 单独监听通过名字或索引判断/// /summarypublicvoidOnDifficultyChanged(boolisOn){// 注意ToggleGroup 切换时会触发两次回调// 一次是旧 Toggle 的 isOnfalse一次是新 Toggle 的 isOntrue// 只处理 isOntrue 的那次if(!isOn)return;Togglecurrent_difficultyGroup.ActiveToggles().FirstOrDefault();if(current!null){Debug.Log($切换到:{current.name});}}}4.3 Dropdown 基础用法与动态填充usingUnityEngine;usingTMPro;usingSystem.Collections.Generic;/// summary/// Dropdown 基础用法 动态填充选项/// /summarypublicclassDropdownExample:MonoBehaviour{[SerializeField]privateTMP_Dropdown_languageDropdown;[SerializeField]privateTMP_Dropdown_resolutionDropdown;voidStart(){// 方式 1Inspector 中手动添加选项适合固定选项 // 直接在 TMP_Dropdown 组件的 Options 列表中添加即可// 方式 2代码动态填充适合运行时生成的选项 SetupResolutionDropdown();// 监听选中变化 _languageDropdown.onValueChanged.AddListener(OnLanguageChanged);_resolutionDropdown.onValueChanged.AddListener(OnResolutionChanged);}privatevoidSetupResolutionDropdown(){// 清空已有选项_resolutionDropdown.ClearOptions();// 创建新选项列表ListstringoptionsnewListstring{1920 x 1080,1280 x 720,2560 x 1440,3840 x 2160};// 添加选项_resolutionDropdown.AddOptions(options);// 设置默认选中项索引从 0 开始_resolutionDropdown.value0;// 刷新显示确保 Caption 文字更新_resolutionDropdown.RefreshShownValue();}privatevoidOnLanguageChanged(intindex){// index 是选中项的索引stringselected_languageDropdown.options[index].text;Debug.Log($语言切换为:{selected});}privatevoidOnResolutionChanged(intindex){stringselected_resolutionDropdown.options[index].text;Debug.Log($分辨率切换为:{selected});}/// summary/// 运行时动态添加单个选项/// /summarypublicvoidAddCustomOption(stringoptionText){_resolutionDropdown.options.Add(newTMP_Dropdown.OptionData(optionText));// 注意添加后不会自动刷新 UI需要手动调用_resolutionDropdown.RefreshShownValue();}voidOnDestroy(){_languageDropdown.onValueChanged.RemoveListener(OnLanguageChanged);_resolutionDropdown.onValueChanged.RemoveListener(OnResolutionChanged);}}4.4 Dropdown 带图标选项usingUnityEngine;usingTMPro;usingSystem.Collections.Generic;/// summary/// Dropdown 带图标的选项如职业选择带职业图标/// /summarypublicclassDropdownWithIconExample:MonoBehaviour{[SerializeField]privateTMP_Dropdown_classDropdown;[SerializeField]privateSprite[]_classIcons;// Inspector 中拖入职业图标voidStart(){_classDropdown.ClearOptions();// 使用 OptionData 同时设置文字和图标 ListTMP_Dropdown.OptionDataoptionsnewListTMP_Dropdown.OptionData{newTMP_Dropdown.OptionData(战士,_classIcons[0]),newTMP_Dropdown.OptionData(法师,_classIcons[1]),newTMP_Dropdown.OptionData(弓箭手,_classIcons[2]),newTMP_Dropdown.OptionData(牧师,_classIcons[3])};_classDropdown.AddOptions(options);// 需要在 Dropdown 的 Template Item 中配置 Item Image 引用// 否则图标不会显示}}5. 使用方法Toggle 开关Hierarchy 右键 → UI →Toggle创建或 UI → Toggle - TextMeshPro选中 Toggle 对象Inspector 中Is On设置初始状态Graphic确认指向 Checkmark 子对象挂载脚本onValueChanged监听状态变化ToggleGroup 单选创建一个空 Panel 作为父对象给 Panel 添加ToggleGroup组件创建多个 Toggle 作为子对象每个 Toggle 的Group属性拖拽指向 PanelAllow Switch Off设为 false强制必须选一个Dropdown 下拉列表Hierarchy 右键 → UI →Dropdown - TextMeshPro创建Inspector 中Options列表手动添加选项固定选项或用代码ClearOptions()AddOptions()动态填充onValueChanged监听选中变化回调参数是 int 索引6. 参数说明Toggle 脚本参数参数类型默认值说明_soundToggleToggle—音效开关 Toggle 引用_musicToggleToggle—音乐开关 Toggle 引用ToggleGroup 脚本参数参数类型默认值说明_difficultyGroupToggleGroup—难度选择的 ToggleGroup 引用Dropdown 脚本参数参数类型默认值说明_languageDropdownTMP_Dropdown—语言选择下拉列表_resolutionDropdownTMP_Dropdown—分辨率选择下拉列表7. 变体与扩展7.1 Toggle 自定义样式图标替换默认的勾选框太朴素可以替换为自定义图标准备两张图未选中状态如空心圆和选中状态如实心圆/星星Background 的 Image 设为未选中图Checkmark 的 Image 设为选中图调整 Checkmark 的 RectTransform 大小和位置也可以用颜色变化代替图标切换// 选中时改变背景颜色toggle.onValueChanged.AddListener(isOn{toggle.GetComponentImage().colorisOn?newColor(0.2f,0.8f,0.4f)// 选中绿色:newColor(0.8f,0.8f,0.8f);// 未选中灰色});7.2 Dropdown 搜索过滤当选项很多时如 100 个道具加一个搜索框过滤// 在 Dropdown 上方放一个 InputField[SerializeField]privateTMP_InputField_searchInput;[SerializeField]privateTMP_Dropdown_dropdown;privateListstring_allOptions;// 完整选项列表voidStart(){_allOptionsnewListstring{长剑,短剑,法杖,弓,盾牌/* ... */};_dropdown.AddOptions(_allOptions);_searchInput.onValueChanged.AddListener(FilterOptions);}privatevoidFilterOptions(stringkeyword){_dropdown.ClearOptions();if(string.IsNullOrEmpty(keyword)){_dropdown.AddOptions(_allOptions);}else{// 过滤包含关键词的选项varfiltered_allOptions.FindAll(optopt.Contains(keyword,System.StringComparison.OrdinalIgnoreCase));_dropdown.AddOptions(filtered);}_dropdown.RefreshShownValue();}7.3 多级联动 Dropdown省 → 市 → 区三级联动// 省份变化时更新城市列表_provinceDropdown.onValueChanged.AddListener(index{stringprovince_provinceDropdown.options[index].text;_cityDropdown.ClearOptions();_cityDropdown.AddOptions(GetCities(province));_cityDropdown.value0;_cityDropdown.RefreshShownValue();});8. 常见问题Q: ToggleGroup 切换时回调触发了两次A: 正常行为。切换时旧 Toggle 的onValueChanged(false)和新 Toggle 的onValueChanged(true)各触发一次。在回调中加if (!isOn) return;只处理选中事件。Q: Toggle 的 Checkmark 不显示/不隐藏A: 检查 Toggle 组件的Graphic属性是否正确指向 Checkmark 对象。如果 Checkmark 是 Background 的子对象确认 Background 的Raycast Target没有遮挡 Toggle 的点击区域。Q: Dropdown 展开后选项列表位置偏了A: 检查 Template 的 RectTransform 锚点和 Pivot。Template 默认锚在 Dropdown 底部向下展开。如果 Dropdown 在屏幕底部列表会被裁切——可以改 Template 的 Pivot 让它向上展开。Q: 代码 AddOptions 后 Dropdown 显示的还是旧文字A: 添加选项后需要调用RefreshShownValue()刷新 Caption 文字。或者设置dropdown.value 0触发一次更新。Q: 原生 Dropdown 和 TMP_Dropdown 有什么区别A: 功能完全一致区别只在文字渲染原生用TextTMP 用TextMeshProUGUI。推荐统一用 TMP 版本文字渲染质量更好且 Unity 新版本已经默认使用 TMP。9. 性能 / 适配建议Toggle 数量几十个 Toggle 完全没有性能问题。如果需要上百个如大型筛选面板考虑用 ScrollRect 对象池动态生成。Dropdown 选项数量Dropdown 展开时会一次性实例化所有选项的 UI 对象。100 个以内没问题1000 个会有明显卡顿。大量选项场景建议自己实现虚拟滚动列表参考本系列后续文章 11。ToggleGroup 的 Allow Switch Off设为 false 时代码中toggle.isOn false不会生效Group 会强制保持至少一个选中。如果需要代码重置先临时设allowSwitchOff true改完再设回来。Dropdown Template 的 Canvas 层级Dropdown 展开时会创建一个新的 Canvas 来渲染列表确保列表在最上层。这个临时 Canvas 会增加一次 Draw Call但关闭后自动销毁。移动端适配Dropdown 在小屏幕上展开可能超出屏幕范围。建议限制 Template 的最大高度设ScrollRect的Content高度上限让选项可滚动而不是无限展开。

更多文章