框架整理学习

UIMgr:

一、数据结构与算法
1.1 关键数据结构

成员变量类型说明
m_CtrlsList<PageInfo>当前正在显示的所有 UI 页面
m_CachesList<PageInfo>已打开过、但现在不显示的页面(缓存池)
1.2 算法逻辑
  • 查找缓存页面:从 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 组件,并手动获取并设置 BaseCtrlBaseView


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_Ctrlsm_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 “时间换空间”?

✅ 空间换时间

意思是:通过多占用内存空间,来提升运行效率(尤其是查找效率)

例如:

  • 创建一个大型的数组或哈希表,快速定位数据。

  • 为了加快访问速度,牺牲一些内存来保存冗余数据或索引。

    ✅ 时间换空间

    意思是:通过减少内存占用,但牺牲一点运行效率(特别是遍历或查找速度)

    例如:

  • 仅保存最少必要信息,每次都从头计算或查找。

  • 不额外保存中间状态,减少内存消耗。

    二、对比 DictionaryList

    特性Dictionary<K, V>List<T>
    本质结构哈希表(Hash Table)数组(Array)
    查找效率O(1) 常数时间(哈希定位)O(n) 线性时间(需要遍历整个列表)
    插入效率快,但哈希冲突时略慢尾部插入快,插入中间则可能慢
    占用内存:维护哈希表结构、桶数组等:仅维护数据本身
    是否保证顺序不保证插入顺序保证插入顺序
    使用场景快速定位、查找、映射(如字典、缓存系统)顺序存储、小集合、频繁遍历
    三、空间换时间的例子(Dictionary)
    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 是“时间换空间”内存占用少,但每次操作如查找需要从头遍历,适合数据量小、频繁顺序处理的场景

 PageInfoBaseCtrlBaseView 是什么?作用是什么?

1. PageInfo:页面的容器(页面元信息)

PageInfo 主要负责绑定以下三件事:

  • 页面类型 EPageType

  • 控制器组件 BaseCtrl

  • 视图组件 BaseView

  • UI 面板 UIPanel(来自 FairyGUI)

  • gameObject 对象本身

它像是一个页面的数据模型,保存了一切有关这个 UI 页面的运行时数据。

2. BaseCtrl:控制器(逻辑层)

所有页面控制器都应该继承自 BaseCtrl,控制器主要负责:

  • 页面交互逻辑(按钮点击、数据更新等)

  • 与服务器、数据层的交互

  • 接收用户操作、修改视图

控制器内部通常引用它的 PageInfoBaseView


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) 或其变种的架构思想。
BaseCtrlBaseView,分别承担:

类名角色职责
BaseCtrlController控制器,负责逻辑处理、按钮响应、事件绑定、数据驱动等
BaseViewView视图,负责界面元素展示、动画、UI 的显示隐藏等视觉内容

它们共同组成了一个页面(PageInfo)的核心功能组合:
PageInfo.m_Ctrl => 逻辑处理器
PageInfo.m_View => UI视图渲染器

这种设计符合高内聚、低耦合的原则。

二、继承结构概览(类图)

[BaseCtrl] <--- [ShopCtrl] / [MainCtrl] / [BagCtrl] ...
[BaseView] <--- [ShopView] / [MainView] / [BagView] ...

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/88575.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/88575.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/88575.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

60 美元玩转 Li-Fi —— 开源 OpenVLC 平台入门(附 BeagleBone Black 驱动简单解析)

60 美元玩转 Li-Fi —— 开源 OpenVLC 平台入门&#xff08;附 BeagleBone Black 及驱动解析&#xff09;一、什么是 OpenVLC&#xff1f; OpenVLC 是由西班牙 IMDEA Networks 研究所推出的开源可见光通信&#xff08;VLC / Li-Fi&#xff09;研究平台。它把硬件、驱动、协议栈…

Python性能优化

Python 以其简洁和易用性著称,但在某些计算密集型或大数据处理场景下,性能可能成为瓶颈。幸运的是,通过一些巧妙的编程技巧,我们可以显著提升Python代码的执行效率。本文将介绍8个实用的性能优化技巧,帮助你编写更快、更高效的Python代码。   一、优化前的黄金法则:先测…

easyui碰到想要去除顶部栏按钮边框

只需要加上 plain"true"<a href"javascript:void(0)" class"easyui-linkbutton" iconCls"icon-add" plain"true"onclick"newCheck()">新增</a>

C++字符串详解:原理、操作及力扣算法实战

一、C字符串简介在C中&#xff0c;字符串的处理方式主要有两种&#xff1a;字符数组&#xff08;C风格字符串&#xff09;和std::string类。虽然字符数组是C语言遗留的底层实现方式&#xff0c;但现代C更推荐使用std::string类&#xff0c;其封装了复杂的操作逻辑&#xff0c;提…

CMU15445-2024fall-project1踩坑经历

p1目录&#xff1a;lRU\_K替换策略LRULRU\_K大体思路SetEvictableRecordAccessSizeEvictRemoveDisk SchedulerBufferPoolNewPageDeletePageFlashPage/FlashAllPageCheckReadPage/CheckWritePagePageGuard并发设计主逻辑感谢CMU的教授们给我们分享了如此精彩的一门课程&#xff…

【C语言进阶】带你由浅入深了解指针【第四期】:数组指针的应用、介绍函数指针

前言上一期讲了数组指针的原理&#xff0c;这一期接着上一期讲述数组指针的应用以及数组参数、函数参数。首先看下面的代码进行上一期内容的复习&#xff0c;pc应该是什么类型&#xff1f;char* arr[5] {0}; xxx pc &arr;分析&#xff1a;①首先判断arr是一个数组&#x…

在HTML中CSS三种使用方式

一、行内样式在标签<>中输入style "属性&#xff1a;属性值;"。(中等使用频率)不利于CSS样式的复用&#xff1b;违背了CSS内容和样式分离的设计理念&#xff0c;后期难以维护。<p style"color: red">这是div中的p元素</p>二、内部样式在…

汽车功能安全-软件单元验证 (Software Unit Verification)【用例导出方法、输出物】8

文章目录1 软件单元验证用例导出方法2 测试用例完整性度量标准3 验证环境要求4 软件单元验证的工作产品1 软件单元验证用例导出方法 为确保软件单元测试的测试案例规范符合9.4.2要求&#xff0c;应通过表8所列方法开发测试用例。 表8 软件单元测试用例的得出方法&#xff1a; …

MySQL内置函数(8)

文章目录前言一、日期函数二、字符串函数三、数学函数四、其它函数总结前言 其实在之前的几篇中我们也用到了内置函数&#xff0c;现在我们再来系统学习一下它&#xff01; 一、日期函数 函数名称描述current_date()获取当前日期current_time()获取当前时间current_timestamp(…

苍穹外卖项目日记(day04)

苍穹外卖|项目日记(day04) 前言: 今天主要是接口开发, 涉及的新东西不多, 需要注意的只有多表联查和修改的逻辑,今日难点: 1.菜品的停起售状态设置 2.套餐的停起售状态设置 3.动态sql中的 useGeneratedKeys 与 keyProperty 两个参数 一. 菜品的停起售状态设置 ​ 在菜品的停售中…

React之旅-05 List Key

每个React的初学者&#xff0c;在调试程序时&#xff0c;都会遇到这样的警告&#xff1a;Warning: Each child in a list should have a unique "key" prop. 如下面的代码&#xff1a; const list [Learn React, Learn GraphQL];const ListWithoutKey () > (&l…

[特殊字符] 人工智能技术全景:从基础理论到前沿应用的深度解析

&#x1f680; 人工智能技术全景&#xff1a;从基础理论到前沿应用的深度解析 在这个AI驱动的时代&#xff0c;理解人工智能的核心技术和应用场景已成为技术人员的必备技能。本文将带你深入探索AI的发展脉络、核心技术差异以及在各行业的创新应用。 文章目录&#x1f680; 人工…

Go语言教程-环境搭建

前言 Go&#xff08;又称 Golang&#xff09;是由 Google 开发的一种 开源、静态类型、编译型 编程语言&#xff0c;于 2009 年正式发布。它旨在解决现代软件开发中的高并发、高性能和可维护性问题&#xff0c;尤其适合 云计算、微服务、分布式系统 等领域。 Go 语言国际官网…

windows指定某node及npm版本下载

下载并安装 nvm-windowshttps://github.com/coreybutler/nvm-windows/releases&#xff08;选择 nvm-setup.zip&#xff09;。打开命令提示符&#xff08;管理员权限&#xff09;&#xff0c;安装 Node.js v16.15.0&#xff1a; nvm install 16.15.0 nvm use 16.15.0 验证node版…

每天一个前端小知识 Day 28 - Web Workers / 多线程模型在前端中的应用实践

Web Workers / 多线程模型在前端中的应用实践&#x1f9e0; 一、为什么前端需要多线程&#xff1f; 单线程 JS 的瓶颈&#xff1a;浏览器主线程不仅负责执行 JS&#xff0c;还要负责&#xff1a; UI 渲染&#xff08;DOM/CSS&#xff09;用户事件处理&#xff08;点击、输入&am…

python:ImportError: cannot import name ‘ParameterSource‘ from ‘click.core‘

浏览器访问网站抛错&#xff1a;ImportError: cannot import name ParameterSource from click.core (E:\environment\python\Lib\site-packages\click\core.py)问题分析&#xff1a;1. click 版本问题ParameterSource 可能是在某个特定版本的 click 库中引入的&#xff0c;而你…

flink 去重

LOCALTIMESTAMP as time_stamp ts as case when time is null then CURRENT_TIMESTAMP else TO_TIMESTAMP_LTZ(time, 0) end , watermark for ts as ts - interval ‘60’ second PARTITION BY 的都有回撤流 group by 的没有回撤流 因为算的是指标 开窗又慢 SELECT * FROM (…

【音视频】TS协议解析

参考博客&#xff1a;https://blog.csdn.net/rell336/article/details/38109621?utm_mediumdistribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_sourcedistribute.pc_relevant_t0.none-task-blog-BlogCommendFromMac…

uniapp 日期组件可选择年月

month-picker 月份选择器组件 组件介绍 month-picker 是一个用于选择年月的自定义组件&#xff0c;基于 uni-app 开发&#xff0c;提供了简洁的月份选择功能。 解决弹框底部出现底部页面区域 safe-area属性设为true时&#xff0c;即可解决这个问题效果如图功能特点 支持选择年份…

从真人到数字分身:3D人脸扫描设备在高校数字人建模教学中的应用

在影视、动漫、游戏等数字创意产业蓬勃发展的当下&#xff0c;超写实虚拟数字人凭借其高度逼真的形象&#xff0c;成为行业关注的焦点。无论是影视特效中栩栩如生的角色&#xff0c;还是游戏里精致的NPC&#xff0c;超写实虚拟数字人的制作都离不开先进的技术支撑。而3D人脸扫描…