基于ET框架和UGUI的简易UI框架(et3.3版)
前言
本框架是在ET框架上进行修改的,使用的是Unity自带的UGUI。
其实ET本身就带有简单的UI框架,建议学习之前先看懂ET里面的UI组件,主要看UIComponent,IUIFactory,UI及与其相关的类,明白ET中整个UI的运作流程。
框架介绍
本框架特点:
1、层级分明,本框架把UI分成5层,层级依次递增,在Unity面板设置好属性后自动加载到该层
2、关闭界面不直接销毁UI物体,而是调用Close方法,并把界面移到UIHiden层进行隐藏,等待下次Show调用,这样可以避免重复加载和实例化UI物体,当你部分UI界面可能出现多次关闭和打开操作时,能减轻运行压力
3、只需进行一次获取引用操作,一般我们会在Awake中通过ReferenceCollector获取需要引用到的物体(例如:返回按钮,输入文本框等),而Show中负责展示界面逻辑(文本框内容初始化,弹出动画等),因为Awake只会调用一次,而Show则每次打开都会调用,所以能减少GetComponent,以及从ReferenceCollector中取出物体的调用,节省性能的开销
4、拓展方便,假如想要拓展什么想要的功能,大部分都可直接在UIBaseComponent中直接修改即可(下面实例拓展了两个我用到的事件OnCloseOneTime和OnClose,大家用不到可直接去掉)
5、当然也可以手动调用UIComponent.Remove()方法进行真正的移除UI操作(直接销毁物体),有需要的也可以自行实现一个定时卸载操作,就是关闭(Close)一定时间后没有再打开(Show)的UI实行移除(Remove),节约内存
本框架主要是先把所有UI分成5层:
不同层根据名字有不同作用,UIHiden比较特殊,而另外的4层根据名称意思,层级逐层递增
UIHiden:隐藏层,当调用Close的时候,实际上是把UI物体移到该层中进行隐藏
Bottom:底层,一般用来放置最底层的UI
Medium:中间层,比较常用,大部分界面均是放在此层
Top:上层,一般是用来放各种弹窗,小窗口之类的
TopMost:最上层,一般用来做各种遮罩层,屏蔽输入,或者切换动画等
Model层
Model层只有两个脚本:UIPanelConfig.cs和WindowLayer.cs
窗体预制体挂上UIPanelConfig组价,填写对应WindowLayer即可
此处WindowLayer用string常量不用枚举是因为热更需要用到Ilrt,而用枚举需要绑定等问题,所以尽量避免使用枚举,应该改成string或其它值常量
// 层级配置 public class UIPanelConfig : MonoBehaviour { public string WindowLayer = ETModel.WindowLayer.Medium; } //窗体层级 public static class WindowLayer { public const string UIHiden = "UIHiden"; public const string Bottom = "Bottom"; public const string Medium = "Medium"; public const string Top = "Top"; public const string TopMost = "TopMost"; } |
如感到实在难受或强迫症患者(强迫症使程序更健壮),可以自行写个Editor类,重写OnInspectorGUI()即可实现和枚举一样的效果,在Inspector视图下选择层级,然后对WindowLayer赋值,替代手动打字,不会的可以自行研究和百度。
Hotfix层
热更层只有5个文件,其中只有UIBaseComponent.cs这个是新增的,其余四个均是修改自et源UI框架的。
// UI窗体主控组件需要继承此类 public abstract class UIBaseComponent : Component { public event Action OnCloseOneTime; public event Action OnShow; public event Action OnClose; public bool InShow { get { return Layer != WindowLayer.UIHiden; } } public string Layer { get; set; } = WindowLayer.UIHiden; public virtual void Show() { GetParent().GameObject.SetActive(true); OnShow?.Invoke(); } public virtual void Close() { GetParent().GameObject.SetActive(false); if (OnCloseOneTime != null) { OnCloseOneTime.Invoke(); OnCloseOneTime = null; } OnClose?.Invoke(); } public override void Dispose() { base.Dispose(); OnCloseOneTime = null; OnShow = null; OnClose = null; Layer = WindowLayer.UIHiden; } } |
所有的窗体主控组件均要继承自此组件,而且每个UI窗体只能存在一个继承自此的组件,用于管理此UI主要行为,如:Show,Close等
PS:OnCloseOneTime和OnClose是因为我项目用到才加的,各位各取所需,不用的可以去掉,或者想要什么功能都可以在这个组件中拓展
Example
此处放上一个模版,各位可以参考一下,也可以根据项目需要自行修改。
UIXXXComponent和UIXXXFactory大概写法和模版差不多,大家可以自行填充逻辑进去,如果觉得每次手动创建麻烦,也可以自行写个工具,每次创建窗体就自动创建模版,本案例不提供(因为我也懒得做了)
UILoginComponent.cs
namespace ETHotfix { [ObjectSystem] public class UILoginComponentAwakeSystem : AwakeSystem { public override void Awake(UILoginComponent self) { self.Awake(); } } public class UILoginComponent : UIBaseComponent//此处继承自UIBaseComponent而不是Component { //Awake方法只调用一次,通常用于获取引用,绑定事件,初始化部分道具 public void Awake() { //获取ReferenceCollector的引用 ReferenceCollector rc = this.GetParent().GameObject.GetComponent(); //通过ReferenceCollector获取添加的物体引用 //此处获取返回按钮的Button组件,并且绑定点击事件 rc.GetUnityComponent<button>("ReturnBtn").Add(OnClickReturnBtn); } //每次Show窗体都会调用,通常用于初始化界面 public override void Show() { base.Show(); //展示界面逻辑 } //关闭时调用 public override void Close() { base.Close(); //关闭界面逻辑 } //点击返回按钮事件 private void OnClickReturnBtn() { //点击退出界面逻辑 } } } </button> |
UILoginFactory.cs
namespace ETHotfix { [UIFactory(UIType_Z.UILogin)] public class UILoginFactory : IUIFactory_Z { public UI_Z Create(Scene scene, string type, GameObject parent) { try { ResourcesComponent resourcesComponent = Game.Scene.GetComponent(); resourcesComponent.LoadBundle($"{type}.unity3d"); GameObject bundleGameObject = resourcesComponent.GetAsset($"{type}.unity3d", $"{type}"); GameObject newUi = UnityEngine.Object.Instantiate(bundleGameObject); newUi.layer = LayerMask.NameToLayer(LayerNames.UI); UI_Z ui = ComponentFactory.Create<UI_Z, GameObject>(newUi); //此处务必使用AddUiComponent代替原本et中的AddComponent否则UI_Z中的UiComponent属性会为空 ui.AddUiComponent(); return ui; } catch (Exception e) { Log.Error(e.ToStr()); return null; } } public void Remove(string type) { Game.Scene.GetComponent().UnloadBundle($"{type}.unity3d"); } } } |
注意:在各个窗体的IUIFactory_Z的实现中,Create方法里面,请务必用ui.AddUiComponent<UIXXXComponent>();代替原本et中的ui.AddComponent<UIXXXComponent>();否则UI_Z中的UiComponent属性会为空
下载:
GitHub(国外):
ET模组仓库: https://github.com/egametang/ET-Modules.git
本人工具仓库:https://github.com/HealthyChina/HealthyResource.git
Gitee(国内):
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)