【Unity UI 进阶】仿 Element UI 打造企业级 Unity UI 组件库(06)
环境与工具说明
| 项 | 说明 |
|---|---|
| 代码生成 | 本系列组件库代码由 Cursor(AI 编程助手)辅助生成与迭代,再结合工程内联调、重构落地 |
| Unity 版本 | 2022.3.50f1c1(Unity 2022.3 LTS) |
| UI 框架 | UGUI(UnityEngine.UI) |
| 示例工程 | EleUnityUI(仿 Element UI 企业级组件库) |
| 图表 | XCharts(Assets/XCharts,只调用公开 API,不改插件源码) |
建议使用 Unity 2022.3 LTS 同系列版本打开工程。本文实现均在
2022.3.50f1c1下验证。上篇(05)讲完独立 Tabs;本篇是后台骨架的另一块------顶部导航EleNavMenu,以及与内容区 / XCharts 的联动。
NavMenu 导航条:1~3 级菜单、默认页、下拉、与内容区 / XCharts
企业后台常见布局:
text
┌─────────────────────────────────────────┐
│ Logo 首页 系统管理 ▼ 流程控制 ▼ 关于 │ ← EleNavMenu 顶栏
├─────────────────────────────────────────┤
│ ContentHost / Page_{code} │ ← 业务页(示例用 XCharts 填充)
│ (首页四宫格 / 用户柱状图 / ...) │
└─────────────────────────────────────────┘
EleNavMenu 仿 Element 顶栏:一级横排、二级下拉、三级侧出;深度由 maxDepth 控制。选中叶子抛 OnNavSelected(code, path),由业务切换内容。Demo 里用 EleNavMenuChartDemoHost 只做显隐切换,页面与图表在 Editor Generate 时烘焙进 Prefab。
本篇覆盖:
- 配置与
maxDepth/ 间距 - 一级项布局、悬停 / 选中高亮、可点击命中区
- 父项默认页 + 点击展开子菜单(挂根 Canvas)
- Prefab 生成约定(禁止运行时拼装兜底)
- 与 XCharts 内容区联动
涉及文件:
| 能力 | 主要文件 |
|---|---|
| 运行时导航 | Runtime/NavMenu/EleNavMenu.cs |
| 配置模型 | Runtime/NavMenu/EleNavMenuModels.cs |
| Config 资产 | Runtime/NavMenu/EleNavMenuConfigAsset.cs |
| Demo 宿主(只切页) | Runtime/NavMenu/EleNavMenuChartDemoHost.cs |
| 图表尺寸适配 | Runtime/NavMenu/EleNavMenuXChartsLayout.cs |
| Editor 烘焙页面 | Editor/NavMenu/EleNavMenuChartPageBuilder.cs |
| 示例生成 | Editor/NavMenu/EleNavMenuSampleGenerator.cs |
颜色走 设计变量 :顶栏 HeaderBg,激活 / 悬停 Primary,文字 TextPrimary / TextRegular,下拉白底 + Border 描边。
工程约定(.cursor/rules/eleunityui-conventions.mdc):
- 不改插件(含 XCharts)
- 新增代码写中文注释
- Prefab 用 Generate 烘焙;运行时禁止缺啥建啥
一、整体结构
1. Demo Prefab 层级
text
EleNavMenuDemo(全屏壳)
├── ContentHost ← 内容在下
│ ├── Page_home ← 首页四宫格(XCharts)
│ ├── Page_user / Page_role / ...
│ ├── Page_flow_overview / Page_flow_nodes
│ └── Page_about
└── EleNavMenu(全屏透明根,最后绘制)
├── NavBar ← 仅顶栏不透明底
│ └── NavRow → Logo + Nav_* 按钮
└── DropdownHost ← 备用区域;实际下拉挂根 Canvas
要点:
- 导航根全屏但 Image 透明 :给布局留高度;不能 用不透明
HeaderBg盖住内容。 - 只有
NavBar画顶栏底色。 - 下拉面板挂到根 Canvas ,
sortingOrder抬高,避免被图表挡住。
2. 数据流
text
EleNavMenuConfig.items(children 嵌套)
→ BuildBar() 生成一级按钮(间距 itemSpacing)
→ 点击叶子 → SelectLeaf(code, path) → OnNavSelected
→ 点击父项 → 切默认叶子页 + ToggleDropdown(挂根 Canvas)
→ DemoHost.ShowPage(code) 只 SetActive Prefab 内 Page_*
业务侧最小接入:
csharp
nav.OnNavSelected += (code, path) =>
{
// code: 叶子编码,如 user
// path: 如 system/user
host.ShowPage(code);
};
二、配置模型
1. 单项 EleNavItemConfig
csharp
new EleNavItemConfig
{
label = "系统管理",
code = "system",
icon = EleUiIcons.Settings, // 空=无图标
enabled = true,
children = new List<EleNavItemConfig> { /* 二级... */ }
}
2. 整体 EleNavMenuConfig
| 字段 | 含义 |
|---|---|
height |
顶栏高度,默认 48 |
maxDepth |
1=仅一级;2=可下拉二级;3=可再侧出三级 |
itemSpacing |
一级项间距,默认 16 |
itemPaddingX |
项内左右 padding,默认 14 |
showLogo / logoText |
左侧品牌圆点(及可选文案) |
dropdownMinWidth |
下拉最小宽度 |
items |
菜单树 |
3. maxDepth 对照
| 值 | 效果 |
|---|---|
| 1 | 仅一级;children 不展开 |
| 2 | 一级 + 向下二级 |
| 3 | 二级行可再侧出三级(如「权限 → 菜单权限」) |
4. 示例菜单树(CreateSample)
| 一级 | 子项(有内容页) |
|---|---|
首页 home |
叶子 → Page_home |
系统管理 system ▼ |
用户 / 角色 / 权限(三级) → Page_user 等 |
流程控制 process ▼ |
流程总览 / 节点监控 |
关于 about |
叶子 → Page_about |
父项本身没有 Page_system / Page_process。点父项会:
- 打开第一个叶子作为默认页(系统管理 → 用户管理;流程控制 → 流程总览)
- 展开子菜单,可再点其它子项
三、一级顶栏:间距、命中、悬停与选中
1. 布局
NavRow使用HorizontalLayoutGroup,spacing = itemSpacing- 按钮宽度按「图标 + 文字 + ▼ + padding」估算,标签宽只按文字,避免图标与文字脱节
- 父项显示明显的 ▼
2. 为什么必须能点中
UGUI 对 alpha=0 的 Graphic 往往不参与射线检测。按钮底图使用极低透明度(如 0.02),文字 / 图标 raycastTarget = false,点击落到整块按钮上。
3. 悬停与选中
| 状态 | 表现 |
|---|---|
| 常态 | 近透明底 + TextPrimary |
| 悬停 | 浅蓝底 + Primary 文字 / 图标 |
| 选中 | 更深浅蓝底 + Primary(含子路径:选中 user 时 system 也高亮) |
选中判断:activeCode 或 activePath 以 code/ 为前缀。
四、子菜单(二级 / 三级)
1. 交互
- 仅点击展开(不在悬停时自动弹出,避免闪关)
- 再点同一父项 → 收起
- 点面板外 → 关闭(打开后忽略 1~2 帧,防止点开即关)
2. 实现要点
text
ShowDropdown
→ 父节点 = rootCanvas.transform(不是只有 48px 高的导航条)
→ 白底 + Outline + 子 Canvas(sortingOrder≈500)
→ 按子项数量定高:count * 40 + padding
→ 用按钮左下角屏幕坐标转到 Canvas 本地定位
三级:ShowSubmenu 贴在二级行右侧,sortingOrder 更高。
3. 踩过的坑(文档化)
| 现象 | 原因 | 处理 |
|---|---|---|
| 有 ▼ 但看不到下拉 | 导航根只有栏高,DropdownHost 高度≈0 | 导航根全屏透明;下拉改挂根 Canvas |
| 内容区整页被盖住 | 全屏根用了不透明 HeaderBg |
根 Image Color.clear,底色只在 NavBar |
| 下拉闪一下消失 | 同帧「点外部关闭」 | _ignoreOutsideClickUntilFrame |
| 图表盖住下拉 | 排序不够 | 下拉独立 Canvas + 高 sortingOrder |
五、Prefab 生成与运行时约定
1. 资源路径
| 资源 | 路径 |
|---|---|
| Config | Resources/NavMenu/EleNavMenuSampleConfig.asset |
| 仅顶栏 Prefab | Prefabs/NavMenu/EleNavMenuSample.prefab |
| 整页 Demo Prefab | Prefabs/NavMenu/EleNavMenuDemo.prefab |
2. 菜单
text
EleUnityUI → Samples → NavMenu → Generate EleNavMenu Sample # 烘焙 Config + Prefab
EleUnityUI → Samples → NavMenu → Spawn EleNavMenu Preview In Scene # 只实例化
EleUnityUI → Samples → NavMenu → Reset EleNavMenu Config To Preset
3. Generate 做什么(Editor)
- 写 / 更新 Config
GenerateNavBarPrefab:顶栏样例GenerateDemoPrefab:全屏壳 + 透明导航根 +ContentHostEleNavMenuChartPageBuilder.BakeAllPages:烘焙全部Page_*与 XChartsFitAllChartsUnder:纠正 XChartsInit强制的 580×300,改回 stretch
4. Spawn / Play 做什么(禁止兜底创建)
csharp
// ✅ 只实例化 + 切已有 Page_*
PrefabUtility.InstantiatePrefab(demoPrefab);
host.CachePagesFromPrefab();
host.ShowPage("home");
// ❌ 运行时发现没有 ContentHost / Page 就 CreateRect、BuildChart
缺 Prefab 时 Spawn 弹窗提示先 Generate,不在 Spawn 里临时拼整页。
5. XCharts 注意
- Chart 与
Image不能同物体 (都是 Graphic)→ 挂在卡片下ChartRoot Init在sizeDelta偏小时会写成 580×300 →EleNavMenuXChartsLayout.FitChartToParent改回拉伸
六、与内容区 / Tabs 的职责划分
| 组件 | 管什么 |
|---|---|
| NavMenu | 跨模块导航(大分区 + 下拉) |
| Tabs | 模块内多视图 |
| Table.showTabs | 同一张表的数据筛选(不是全局导航) |
| DemoHost | 按 code 显隐 Page_*(可换成你自己的路由) |
典型组合:顶栏 Nav → 某 Page_* 里再放 Tabs / Table。
七、API 一览
| API / 事件 | 说明 |
|---|---|
SetConfig(config, rebuild) |
换配置并重建顶栏 |
Rebuild() / EditorRebuild() |
Editor「按 Config 重建」 |
SelectNav(code, path, notify) |
代码选中 |
OnNavSelected |
(code, path) |
ActiveCode / ActivePath |
当前叶子与路径 |
DemoHost.ShowPage(code) |
只切换已烘焙页 |
DemoHost.CachePagesFromPrefab() |
收集 Page_* |
八、落地检查清单
- Generate 后存在
EleNavMenuDemo.prefab,且ContentHost下有多个Page_* - Spawn 后能看到首页四宫格;顶栏未盖住内容
- 一级项间距正常;悬停 / 选中高亮
- 父项有明显 ▼ ;点击弹出白底子菜单(Console 有
打开下拉日志) - 点「用户管理」等子项内容切换正确
- 未改过
Assets/XCharts源码 - 改菜单配置后重新 Generate,不要依赖 Play 时自动拼页
九、小结
- EleNavMenu = 透明全屏根 + 不透明
NavBar+ 挂根 Canvas 的下拉 maxDepth/itemSpacing/ Logo 配置驱动- 父项 = 默认叶子页 + 点击展开子菜单;内容在子项
Page_* - Demo 页面与图表 Editor 烘焙;运行时只切显隐
- XCharts 只作适配调用;图表 stretch 适配分辨率
系列回顾与下篇
| 篇 | 内容 |
|---|---|
| 04 | Table 下:选中、列显示、工具栏与弹窗 |
| 05 | Tabs:图标、下划线、内容面板 |
| 06 | NavMenu:1~3 级、默认页、下拉、XCharts Demo(本文) |
07|ContextMenu 右键菜单 :挂载目标、ShowAt、danger / divider / 子菜单,以及点外部关闭与 NavMenu 下拉的异同。
若你在 UGUI 里也遇到过「全屏导航根盖住内容」或「下拉挂在 48px 高的父节点里」,欢迎留言------透明根 + 下拉挂根 Canvas,就是为此准备的。