热门标签 | 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逻辑。
推荐阅读
  • 本文详细介绍了Akka中的BackoffSupervisor机制,探讨其在处理持久化失败和Actor重启时的应用。通过具体示例,展示了如何配置和使用BackoffSupervisor以实现更细粒度的异常处理。 ... [详细]
  • 本文详细介绍了Java中org.neo4j.helpers.collection.Iterators.single()方法的功能、使用场景及代码示例,帮助开发者更好地理解和应用该方法。 ... [详细]
  • 本文探讨了在Java中实现系统托盘最小化的两种方法:使用SWT库和JDK6自带的功能。通过这两种方式,开发者可以创建跨平台的应用程序,使窗口能够最小化到系统托盘,并提供丰富的交互功能。 ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • 本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ... [详细]
  • 在前两篇文章中,我们探讨了 ControllerDescriptor 和 ActionDescriptor 这两个描述对象,分别对应控制器和操作方法。本文将基于 MVC3 源码进一步分析 ParameterDescriptor,即用于描述 Action 方法参数的对象,并详细介绍其工作原理。 ... [详细]
  • Android 渐变圆环加载控件实现
    本文介绍了如何在 Android 中创建一个自定义的渐变圆环加载控件,该控件已在多个知名应用中使用。我们将详细探讨其工作原理和实现方法。 ... [详细]
  • 本题探讨如何通过最大流算法解决农场排水系统的设计问题。题目要求计算从水源点到汇合点的最大水流速率,使用经典的EK(Edmonds-Karp)和Dinic算法进行求解。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 本文介绍如何使用Objective-C结合dispatch库进行并发编程,以提高素数计数任务的效率。通过对比纯C代码与引入并发机制后的代码,展示dispatch库的强大功能。 ... [详细]
  • 本文详细介绍如何使用Python进行配置文件的读写操作,涵盖常见的配置文件格式(如INI、JSON、TOML和YAML),并提供具体的代码示例。 ... [详细]
  • 本文介绍了一款用于自动化部署 Linux 服务的 Bash 脚本。该脚本不仅涵盖了基本的文件复制和目录创建,还处理了系统服务的配置和启动,确保在多种 Linux 发行版上都能顺利运行。 ... [详细]
  • 本文详细介绍了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。 ... [详细]
  • 本文详细介绍了中央电视台电影频道的节目预告,并通过专业工具分析了其加载方式,确保用户能够获取最准确的电视节目信息。 ... [详细]
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社区 版权所有