Unity客户端框架设计:UI管理系统的构建
作者:living_ren | 来源:互联网 | 2024-12-27 10:28
本文详细介绍了如何构建一个高效的UI管理系统,集中处理UI页面的打开、关闭、层级管理和页面跳转等问题。通过UIManager统一管理外部切换逻辑,实现功能逻辑分散化和代码复用,支持多人协作开发。
在Unity客户端框架设计中,UI管理系统的构建是至关重要的部分。一个好的UI框架可以有效解决UI页面的打开、关闭、层级管理和页面跳转等问题,并将这些操作集中管理,从而简化开发流程,提高开发效率。 ### UI管理系统的核心特点 1. **集中管理**:所有UI页面的打开、关闭、层级管理和页面跳转等操作都由UIManager统一管理,确保外部切换逻辑的一致性和可靠性。 2. **功能逻辑分散化**:每个UI页面维护自身的逻辑,依托于框架进行开发,开发者无需关心具体的跳转和显示关闭细节,便于多人协同开发。 3. **代码复用和经验沉淀**:通用性框架能够做到简单的代码复用,积累项目经验,提升开发效率。 4. **兼容多种UI工具**:该框架不仅适用于NGUI和UGUI,还可以扩展到其他UI工具。 ### BaseUI类的设计 BaseUI类是UI页面的基础类,提供了缓存、状态管理和事件触发等功能。以下是BaseUI类的主要代码示例: ```csharp public abstract class BaseUI : MonoBehaviour { private Transform _CachedTransform; public Transform cachedTransform { get { if (_CachedTransform == null) _CachedTransform = this.transform; return _CachedTransform; } } private GameObject _CachedGameobject; public GameObject cachedGameobject { get { if (_CachedGameobject == null) _CachedGameobject = this.gameObject; return _CachedGameobject; } } protected EnumObjectState state = EnumObjectState.None; public event StateChangedEvent StateChanged; public EnumObjectState State { get { return this.state; } set { if (value != state) { EnumObjectState oldState = value; state = value; if (StateChanged != null) StateChanged(this, state, oldState); } } } public abstract EnumUIType GetUIType(); public virtual void SetDepthToTop() { } void Start() { OnStart(); } void Awake() { this.State = EnumObjectState.Initial; OnAwake(); } void Update() { if (EnumObjectState.Ready == State) OnUpdate(Time.deltaTime); } public void Release() { this.State = EnumObjectState.Closing; ObjPool.Instance.OnReturnObj(cachedGameobject); OnRelease(); } protected virtual void OnStart() { } protected virtual void OnAwake() { this.State = EnumObjectState.Loading; this.OnPlayOpenUIAudio(); } protected virtual void OnUpdate(float deltaTime) { } protected virtual void OnRelease() { this.OnPlayCloseUIAudio(); } protected virtual void OnPlayOpenUIAudio() { } protected virtual void OnPlayCloseUIAudio() { } protected virtual void SetUI(params object[] uiParams) { this.State = EnumObjectState.Loading; } protected virtual void OnLoadData() { } public void SetUIWhenOpening(params object[] uiParams) { SetUI(uiParams); CoroutineInstance.Instance.StartCoroutine(AsyncOnLoadData()); } private IEnumerator AsyncOnLoadData() { yield return new WaitForSeconds(0); if (this.State == EnumObjectState.Loading) { this.OnLoadData(); this.State = EnumObjectState.Ready; } } } ``` ### UIManager类的设计 UIManager类负责UI页面的加载、预加载、打开和关闭等操作。以下是UIManager类的主要代码示例: ```csharp public class UIManager : Singleton { private Dictionary dicOpenedUIs = null; private Stack stackOpeningUIs = null; public override void Init() { dicOpenedUIs = new Dictionary(); stackOpeningUIs = new Stack(); } public T GetUI(EnumUIType type) where T : BaseUI { GameObject retObj = GetUIObject(type); if (retObj != null) return retObj.GetComponent(); return null; } public GameObject GetUIObject(EnumUIType type) { if (!dicOpenedUIs.TryGetValue(type, out GameObject retObj)) throw new Exception("dicOpenedUIs TryGetValue Failure! _uiType :" + type.ToString()); return retObj; } public void PreloadUI(EnumUIType[] uiTypes) { foreach (var uiType in uiTypes) PreloadUI(uiType); } public void PreloadUI(EnumUIType uiType) { string path = UIPathDefines.UI_PREFAB + uiType.ToString(); ResManager.Instance.Load(path); } public void OpenUI(EnumUIType[] uiTypes) { OpenUI(false, uiTypes, null); } public void OpenUI(EnumUIType uiType, params object[] uiObjParams) { OpenUI(false, new[] { uiType }, uiObjParams); } public void OpenUICloseOthers(EnumUIType[] uiTypes) { OpenUI(true, uiTypes, null); } public void OpenUICloseOthers(EnumUIType uiType, params object[] uiObjParams) { OpenUI(true, new[] { uiType }, uiObjParams); } private void OpenUI(bool isCloseOthers, EnumUIType[] uiTypes, params object[] uiParams) { if (isCloseOthers) CloseUIAll(); foreach (var uiType in uiTypes) { if (!dicOpenedUIs.ContainsKey(uiType)) stackOpeningUIs.Push(new UIInfoData(uiType, UIPathDefines.UI_PREFAB + uiType.ToString(), uiParams)); } if (stackOpeningUIs.Count > 0) CoroutineInstance.Instance.StartCoroutine(AsyncLoadData()); } private IEnumerator AsyncLoadData() { while (stackOpeningUIs.Count > 0) { var uiInfoData = stackOpeningUIs.Pop(); var prefabObj = ObjPool.Instance.OnGetObj(uiInfoData.Path.Split('/')[1], uiInfoData.Path.Split('/')[0]); prefabObj.transform.SetParent(null); if (prefabObj != null) { var baseUI = prefabObj.GetComponent(); if (baseUI == null) baseUI = prefabObj.AddComponent(uiInfoData.ScriptType) as BaseUI; if (baseUI != null) baseUI.SetUIWhenOpening(uiInfoData.UIParams); dicOpenedUIs.Add(uiInfoData.UIType, prefabObj); } } yield return 0; } public void CloseUI(EnumUIType uiType) { if (dicOpenedUIs.TryGetValue(uiType, out GameObject uiObj)) CloseUI(uiType, uiObj); } public void CloseUI(EnumUIType[] uiTypes) { foreach (var uiType in uiTypes) CloseUI(uiType); } public void CloseUIAll() { foreach (var uiType in new List(dicOpenedUIs.Keys)) CloseUI(uiType, dicOpenedUIs[uiType]); dicOpenedUIs.Clear(); } private void CloseUI(EnumUIType uiType, GameObject uiObj) { if (uiObj == null) dicOpenedUIs.Remove(uiType); else { var baseUI = uiObj.GetComponent(); if (baseUI != null) { baseUI.StateChanged += CloseUIHandler; baseUI.Release(); } else { GameObject.Destroy(uiObj); dicOpenedUIs.Remove(uiType); } } } private void CloseUIHandler(object sender, EnumObjectState newState, EnumObjectState oldState) { if (newState == EnumObjectState.Closing) { var baseUI = sender as BaseUI; dicOpenedUIs.Remove(baseUI.GetUIType()); baseUI.StateChanged -= CloseUIHandler; } } } ``` ### 枚举与静态类 为了更好地管理和定义UI类型及路径,我们使用了枚举和静态类。以下是相关代码示例: ```csharp namespace TownsFramework { public delegate void StateChangedEvent(object sender, EnumObjectState n, EnumObjectState o); public enum EnumObjectState { None, Initial, Loading, Ready, Disabled, Closing } public enum EnumUIType : int { NOne= -1, StartUI, WarUI } public static class UIPathDefines { public const string UI_PREFAB = "UIPrefab/"; public const string UI_CONTROLS_PREFAB = "UIPrefab/Control/"; public const string UI_SUBUI_PREFAB = "UIPrefab/SubUI/"; public const string UI_ICON = "UI/Icon"; public static System.Type GetUIScriptByType(EnumUIType type) { switch (type) { case EnumUIType.StartUI: return typeof(StratUI); case EnumUIType.WarUI: return typeof(WarUI); default: Debug.Log("No This UIType : " + type.ToString()); break; } return null; } } } ``` 以上代码展示了如何构建一个高效且易于扩展的UI管理系统,帮助开发者更轻松地管理复杂的UI逻辑。
推荐阅读
本文详细介绍了Akka中的BackoffSupervisor机制,探讨其在处理持久化失败和Actor重启时的应用。通过具体示例,展示了如何配置和使用BackoffSupervisor以实现更细粒度的异常处理。 ...
[详细]
蜡笔小新 2024-12-27 15:04:09
本文详细介绍了Java中org.neo4j.helpers.collection.Iterators.single()方法的功能、使用场景及代码示例,帮助开发者更好地理解和应用该方法。 ...
[详细]
蜡笔小新 2024-12-28 10:51:55
本文探讨了在Java中实现系统托盘最小化的两种方法:使用SWT库和JDK6自带的功能。通过这两种方式,开发者可以创建跨平台的应用程序,使窗口能够最小化到系统托盘,并提供丰富的交互功能。 ...
[详细]
蜡笔小新 2024-12-25 15:03:50
本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ...
[详细]
蜡笔小新 2024-12-28 09:46:23
本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ...
[详细]
蜡笔小新 2024-12-27 17:31:41
在前两篇文章中,我们探讨了 ControllerDescriptor 和 ActionDescriptor 这两个描述对象,分别对应控制器和操作方法。本文将基于 MVC3 源码进一步分析 ParameterDescriptor,即用于描述 Action 方法参数的对象,并详细介绍其工作原理。 ...
[详细]
蜡笔小新 2024-12-27 15:26:10
本文介绍了如何在 Android 中创建一个自定义的渐变圆环加载控件,该控件已在多个知名应用中使用。我们将详细探讨其工作原理和实现方法。 ...
[详细]
蜡笔小新 2024-12-27 13:34:19
本题探讨如何通过最大流算法解决农场排水系统的设计问题。题目要求计算从水源点到汇合点的最大水流速率,使用经典的EK(Edmonds-Karp)和Dinic算法进行求解。 ...
[详细]
蜡笔小新 2024-12-25 17:47:23
本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ...
[详细]
蜡笔小新 2024-12-28 10:36:30
本文介绍如何使用Objective-C结合dispatch库进行并发编程,以提高素数计数任务的效率。通过对比纯C代码与引入并发机制后的代码,展示dispatch库的强大功能。 ...
[详细]
蜡笔小新 2024-12-28 08:44:35
本文详细介绍如何使用Python进行配置文件的读写操作,涵盖常见的配置文件格式(如INI、JSON、TOML和YAML),并提供具体的代码示例。 ...
[详细]
蜡笔小新 2024-12-28 08:39:55
本文介绍了一款用于自动化部署 Linux 服务的 Bash 脚本。该脚本不仅涵盖了基本的文件复制和目录创建,还处理了系统服务的配置和启动,确保在多种 Linux 发行版上都能顺利运行。 ...
[详细]
蜡笔小新 2024-12-27 16:33:32
本文详细介绍了Java中org.eclipse.ui.forms.widgets.ExpandableComposite类的addExpansionListener()方法,并提供了多个实际代码示例,帮助开发者更好地理解和使用该方法。这些示例来源于多个知名开源项目,具有很高的参考价值。 ...
[详细]
蜡笔小新 2024-12-27 16:11:49
本文介绍了一段通用代码示例,该代码不仅能够操作 Azure Active Directory (AAD),还可以通过 Azure Service Principal 的授权访问和管理 Azure 订阅资源。Azure 的架构可以分为两个层级:AAD 和 Subscription。 ...
[详细]
蜡笔小新 2024-12-27 16:07:12
本文详细介绍了中央电视台电影频道的节目预告,并通过专业工具分析了其加载方式,确保用户能够获取最准确的电视节目信息。 ...
[详细]
蜡笔小新 2024-12-25 21:01:14
living_ren
这个家伙很懒,什么也没留下!