前言
本框架是在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";
}
image
如感到实在难受或强迫症患者(强迫症使程序更健壮),可以自行写个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<UI_Z>().GameObject.SetActive(true);
OnShow?.Invoke();
}
public virtual void Close()
{
GetParent<UI_Z>().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是因为我项目用到才加的,各位各取所需,不用的可以去掉,或者想要什么功能都可以在这个组件中拓展
注意:在各个窗体的IUIFactory_Z的实现中,Create方法里面,请务必用ui.AddUiComponent();代替原本et中的ui.AddComponent();否则UI_Z中的UiComponent属性会为空
Example
此处放上一个模版,各位可以参考一下,也可以根据项目需要自行修改。
UIXXXComponent和UIXXXFactory大概写法和模版差不多,大家可以自行填充逻辑进去,如果觉得每次手动创建麻烦,也可以自行写个工具,每次创建窗体就自动创建模版,本案例不提供(因为我也懒得做了)
namespace ETHotfix
{
[ObjectSystem]
public class UILoginComponentAwakeSystem : AwakeSystem<UILoginComponent>
{
public override void Awake(UILoginComponent self)
{
self.Awake();
}
}
public class UILoginComponent : UIBaseComponent//此处继承自UIBaseComponent而不是Component
{
//Awake方法只调用一次,通常用于获取引用,绑定事件,初始化部分道具
public void Awake()
{
//获取ReferenceCollector的引用
ReferenceCollector rc = this.GetParent<UI_Z>().GameObject.GetComponent<ReferenceCollector>();
//通过ReferenceCollector获取添加的物体引用
//此处获取返回按钮的Button组件,并且绑定点击事件
rc.GetUnityComponent<Button>("ReturnBtn").Add(OnClickReturnBtn);
}
//每次Show窗体都会调用,通常用于初始化界面
public override void Show()
{
base.Show();
//展示界面逻辑
}
//关闭时调用
public override void Close()
{
base.Close();
//关闭界面逻辑
}
//点击返回按钮事件
private void OnClickReturnBtn()
{
//点击退出界面逻辑
}
}
}
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>();
resourcesComponent.LoadBundle($"{type}.unity3d");
GameObject bundleGameObject = resourcesComponent.GetAsset<GameObject>($"{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<UILoginComponent>();
return ui;
}
catch (Exception e)
{
Log.Error(e.ToStr());
return null;
}
}
public void Remove(string type)
{
Game.Scene.GetComponent<ResourcesComponent>().UnloadBundle($"{type}.unity3d");
}
}
}
下载:
GitHub(国外):
ET模组仓库:https://github.com/egametang/ET-Modules.git
本人工具仓库:https://github.com/HealthyChina/HealthyResource.git
Gitee(国内):
本人工具仓库:https://gitee.com/healthyZ/HealthyResource.git
转载请声明出处和作者(渐渐),你的点赞,分享,转发将是对我最大的鼓励!
码字不易,感谢阅读!
网友评论