热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Unity客户端框架设计:UI管理系统的构建

本文详细介绍了如何构建一个高效的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逻辑。
推荐阅读
  • 本文详细介绍了 Apache Jena 库中的 Txn.executeWrite 方法,通过多个实际代码示例展示了其在不同场景下的应用,帮助开发者更好地理解和使用该方法。 ... [详细]
  • 深入解析Spring Cloud Ribbon负载均衡机制
    本文详细介绍了Spring Cloud中的Ribbon组件如何实现服务调用的负载均衡。通过分析其工作原理、源码结构及配置方式,帮助读者理解Ribbon在分布式系统中的重要作用。 ... [详细]
  • 本文详细介绍了Java中org.eclipse.ui.forms.widgets.ExpandableComposite类的addExpansionListener()方法,并提供了多个实际代码示例,帮助开发者更好地理解和使用该方法。这些示例来源于多个知名开源项目,具有很高的参考价值。 ... [详细]
  • 使用 Azure Service Principal 和 Microsoft Graph API 获取 AAD 用户列表
    本文介绍了一段通用代码示例,该代码不仅能够操作 Azure Active Directory (AAD),还可以通过 Azure Service Principal 的授权访问和管理 Azure 订阅资源。Azure 的架构可以分为两个层级:AAD 和 Subscription。 ... [详细]
  • 本文详细介绍了Akka中的BackoffSupervisor机制,探讨其在处理持久化失败和Actor重启时的应用。通过具体示例,展示了如何配置和使用BackoffSupervisor以实现更细粒度的异常处理。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 从 .NET 转 Java 的自学之路:IO 流基础篇
    本文详细介绍了 Java 中的 IO 流,包括字节流和字符流的基本概念及其操作方式。探讨了如何处理不同类型的文件数据,并结合编码机制确保字符数据的正确读写。同时,文中还涵盖了装饰设计模式的应用,以及多种常见的 IO 操作实例。 ... [详细]
  • Scala 实现 UTF-8 编码属性文件读取与克隆
    本文介绍如何使用 Scala 以 UTF-8 编码方式读取属性文件,并实现属性文件的克隆功能。通过这种方式,可以确保配置文件在多线程环境下的一致性和高效性。 ... [详细]
  • ASP.NET MVC中Area机制的实现与优化
    本文探讨了在ASP.NET MVC框架中,如何通过Area机制有效地组织和管理大规模应用程序的不同功能模块。通过合理的文件夹结构和命名规则,开发人员可以更高效地管理和扩展项目。 ... [详细]
  • 本文详细介绍了中央电视台电影频道的节目预告,并通过专业工具分析了其加载方式,确保用户能够获取最准确的电视节目信息。 ... [详细]
  • 使用GDI的一些AIP函数我们可以轻易的绘制出简 ... [详细]
  • 毕业设计:基于机器学习与深度学习的垃圾邮件(短信)分类算法实现
    本文详细介绍了如何使用机器学习和深度学习技术对垃圾邮件和短信进行分类。内容涵盖从数据集介绍、预处理、特征提取到模型训练与评估的完整流程,并提供了具体的代码示例和实验结果。 ... [详细]
  • 利用决策树预测NBA比赛胜负的Python数据挖掘实践
    本文通过使用2013-14赛季NBA赛程与结果数据集以及2013年NBA排名数据,结合《Python数据挖掘入门与实践》一书中的方法,展示如何应用决策树算法进行比赛胜负预测。我们将详细讲解数据预处理、特征工程及模型评估等关键步骤。 ... [详细]
  • 本文介绍了如何在 C# 和 XNA 框架中实现一个自定义的 3x3 矩阵类(MMatrix33),旨在深入理解矩阵运算及其应用场景。该类参考了 AS3 Starling 和其他相关资源,以确保算法的准确性和高效性。 ... [详细]
  • Android 渐变圆环加载控件实现
    本文介绍了如何在 Android 中创建一个自定义的渐变圆环加载控件,该控件已在多个知名应用中使用。我们将详细探讨其工作原理和实现方法。 ... [详细]
author-avatar
living_ren
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有