框架整理学习
UIMgr:
一、数据结构与算法
1.1 关键数据结构
1.2 算法逻辑
成员变量 类型 说明 m_Ctrls
List<PageInfo>
当前正在显示的所有 UI 页面 m_Caches
List<PageInfo>
已打开过、但现在不显示的页面(缓存池)
查找缓存页面:从
m_Caches
中倒序查找是否已有对应ePageType
页面,找到则重用。页面加载:从资源管理器
ResMgr
加载 prefab 并绑定控制器/视图组件。页面关闭:从
m_Ctrls
移除,添加到m_Caches
,供后续复用。刷新页面:关闭当前页面再重新打开。
这些逻辑大多采用线性搜索(O(n)),足够应对中小型游戏中的 UI 数量。
二、基本语法与结构说明
2.1 类继承
public class UIMgr : Singleton<UIMgr>
继承自泛型单例
Singleton<T>
,保证UIMgr
全局唯一实例,可通过UIMgr.Inst
获取。
2.2 组件挂载与初始化ResMgr.Inst.Get(name, null, Constant.m_UiPath).AddComponent<PageInfo>();
加载 UI prefab 后添加
PageInfo
组件,并手动获取并设置BaseCtrl
和BaseView
。
2.3 控制器与视图绑定ctrl.m_PageInfo = showPage; view.m_PageInfo = showPage;
通过双向引用让页面、控制器和视图互相关联。
✅ 三、实现思路详解
3.1 UI 生命周期管理
view.Init(); ctrl.Init(); ctrl.Show(); view.Show();
初始化(
Init
):绑定数据、设置 UI 元素初始状态显示(
Show
):打开 UI 页面隐藏(
UnShow
):关闭 UI 页面,但不销毁对象
3.2 缓存复用机制
UI 关闭时并不直接销毁,而是放入m_Caches
中,节省加载资源开销,提高性能。
3.3 事件广播机制
EventMgr.Inst.Broadcast(IntEvt.Fetch(EventId.OpenUI, ...));
3.4 灵活的关闭方式(函数重载)
支持通过:
页面类型(
EPageType
)控制器(
BaseCtrl
)视图(
BaseView
)页面信息(
PageInfo
)等不同方式关闭页面。
✅ 四、补充建议与未来优化方向
数据结构优化
问题 建议 线性查找效率较低 将 m_Ctrls
和m_Caches
改为Dictionary<EPageType, PageInfo>
,可快速查找页面缓存永不销毁,可能内存溢出 定期检查 m_Caches
长度,进行清理(LRU 算法或设置上限)
解耦结构设计当前逻辑是“管理器 + 控制器 + 视图”三层结构,推荐引入更标准的 UI 框架设计模式,例如:
MVC(Model-View-Controller)
MVVM(Model-View-ViewModel)
ECS(Entity Component System) —— 用于大型项目
异步加载支持
如果资源加载较慢,建议将:ResMgr.Inst.Get(...)
替换为异步方法,支持 loading 动画和取消操作。
动态层级系统
目前层级(sortingOrder)是注释掉的,建议恢复并基于m_Crrls.Count自动设置:showPage.GetComponent<UIPanel>().sortingOrder = m_Ctrls.Count;
确保 UI 正确叠加,避免层级错乱。
✅ 五、总结:
优点 💡 不足点 ⚠️ 简洁明了、结构清晰 查找效率低、资源管理偏静态 支持多种关闭方式 缓存机制缺乏清理策略 模块化控制器与视图 控制器与视图绑定写死在框架中
✅ 一、什么是
Dictionary<EPageType, PageInfo>
?
Dictionary<K, V>
是 C# 中的一种泛型集合类,也叫 字典、哈希表,它存储的是 “键-值对(Key-Value Pair)”:Dictionary<K, V>
K
是键(Key)类型,必须是唯一的。
V
是值(Value)类型,可以重复。
在你的场景中:
Dictionary<EPageType, PageInfo>
EPageType
是一个枚举类型(表示页面类型,例如:主页、背包、商店)
PageInfo
是页面的信息类,包含了 Controller 和 View 以及一些元数据。
✅ 举个例子:
var dic = new Dictionary<EPageType,PageInfo>(); dic[EPageType.Home] = homePageInfo; dic[EPageType.Shop] = shopPageInfo; //获取 var page = dic[EPageType.Home];
相比于
List<PageInfo>
,使用Dictionary
的最大优势是:查找速度是 O(1),非常快!
Dictionary空间换时间 和 List 时间换空间。
一、什么是“空间换时间” vs “时间换空间”?
✅ 空间换时间
意思是:通过多占用内存空间,来提升运行效率(尤其是查找效率)。
例如:
创建一个大型的数组或哈希表,快速定位数据。
为了加快访问速度,牺牲一些内存来保存冗余数据或索引。
✅ 时间换空间
意思是:通过减少内存占用,但牺牲一点运行效率(特别是遍历或查找速度)。
例如:
仅保存最少必要信息,每次都从头计算或查找。
不额外保存中间状态,减少内存消耗。
二、对比Dictionary
和List
三、空间换时间的例子(Dictionary)
特性 Dictionary<K, V>
List<T>
本质结构 哈希表(Hash Table) 数组(Array) 查找效率 O(1) 常数时间(哈希定位) O(n) 线性时间(需要遍历整个列表) 插入效率 快,但哈希冲突时略慢 尾部插入快,插入中间则可能慢 占用内存 高:维护哈希表结构、桶数组等 低:仅维护数据本身 是否保证顺序 不保证插入顺序 保证插入顺序 使用场景 快速定位、查找、映射(如字典、缓存系统) 顺序存储、小集合、频繁遍历
Dictionary<EPageType, PageInfo> uiPages;
背后的原理是:
系统为每个
Key
计算哈希值(比如将EPageType.Shop
映射为 13573)。根据哈希值快速跳转到该数据的内存地址。
这种方式会使用额外的内存结构(如哈希桶、数组、链表等)来保证快速访问。这就是典型的用空间换时间:提高速度,但牺牲内存。
不需要遍历,直接就能拿到结果。
四、时间换空间的例子(List)
List<PageInfo> uiPages;
你只能写:
foreach (var page in uiPages) { if (page.Type == EPageType.Shop) { return page; } }
此时:
查找每个元素需要 O(n) 时间。
不需要额外的哈希结构,节省内存。
数据越多,性能下降越明显。
这是时间换空间:节省内存,但牺牲了执行效率。
五、现实生活类比
场景 类比解释 Dictionary
图书馆:一本书有唯一编号(哈希值),你可以一秒钟定位这本书的位置(快速查找)。为了这个,你得先建一套编号系统,占用一定资源(空间)。 List
堆书桌:书都堆一起了,你要找《C#教程》,只能一本本翻过去,慢,但不需要额外占地(空间节省)。
总结一句话:
类别 定义 Dictionary 是“空间换时间” 用更多的内存结构(如哈希表)来提升数据查找速度,适合频繁查找、修改的数据集合 List 是“时间换空间” 内存占用少,但每次操作如查找需要从头遍历,适合数据量小、频繁顺序处理的场景
PageInfo
、BaseCtrl
、BaseView
是什么?作用是什么?1.
PageInfo
:页面的容器(页面元信息)
PageInfo
主要负责绑定以下三件事:
页面类型
EPageType
控制器组件
BaseCtrl
视图组件
BaseView
UI 面板
UIPanel
(来自 FairyGUI)
gameObject
对象本身它像是一个页面的数据模型,保存了一切有关这个 UI 页面的运行时数据。
2.BaseCtrl
:控制器(逻辑层)
所有页面控制器都应该继承自
BaseCtrl
,控制器主要负责:
页面交互逻辑(按钮点击、数据更新等)
与服务器、数据层的交互
接收用户操作、修改视图
控制器内部通常引用它的
PageInfo
和BaseView
。
3.BaseView
:视图(表现层)
视图负责:
加载 UI 元素
控制 UI 的显示/隐藏、动效
响应控制器的命令
视图绑定在 prefab(预制体)上,显示在屏幕上。你可以在
InitRoot()
中绑定 UI 组件:
view.m_Panel = showPage.gameObject.GetComponent<UIPanel>(); view.InitRoot(view.m_Panel.ui);
总结整体结构图
UIMgr(单例管理器) ├── Dictionary<EPageType, PageInfo> m_Ctrls // 当前显示页面 ├── Dictionary<EPageType, PageInfo> m_Caches // 缓存页面 │ ├── PageInfo(页面信息) │ ├── EPageType m_PageType │ ├── BaseCtrl m_Ctrl │ └── BaseView m_View │ ├── BaseCtrl(控制器) │ └── 控制逻辑、处理事件、更新视图 │ └── BaseView(视图) └── 处理 UI 表现、动画、组件显示
BaseCtrl & BaseView 是什么?职责划分?
在 UI 框架中,通常采用 MVC(Model-View-Controller) 或其变种的架构思想。
BaseCtrl
和BaseView
,分别承担:
类名 角色 职责 BaseCtrl
Controller 控制器,负责逻辑处理、按钮响应、事件绑定、数据驱动等 BaseView
View 视图,负责界面元素展示、动画、UI 的显示隐藏等视觉内容
它们共同组成了一个页面(PageInfo
)的核心功能组合:PageInfo.m_Ctrl => 逻辑处理器 PageInfo.m_View => UI视图渲染器
这种设计符合高内聚、低耦合的原则。
二、继承结构概览(类图)
[BaseCtrl] <--- [ShopCtrl] / [MainCtrl] / [BagCtrl] ... [BaseView] <--- [ShopView] / [MainView] / [BagView] ...