当一个程序的界面多达十几、几十个的时候,若是没有一个框架管理UI界面的跳转、数据传递,一定会感觉很混乱,总会拉下一两个,程序就会出现问题,你认为你很小心,不会有问题,当你看到大量代码都在控制UI界面的显示隐藏上,你会忍不住抓狂吗?
不会偷懒的程序猿不是一个合格的程序猿,
这时候一个合适的框架帮你管理UI界面,你会省心不少,省下很多不必要的时间
UI框架简单版
核心思想
- 把程序的UI界面做成预制体,等到需要用到的时候加载
- 把所有的UI界面的名字、路径保存成配置文件
- 编写基类,基类包括所有界面的通用操作(界面的进入、界面的退出、界面的刷新。。。)
- 编写管理类,管理类是一个单例对象,管理类使用字典(Dictionary)保存所有界面路径、界面对象实体和一个用来记录程序操作的栈(Stack)
实践是检验真理的唯一标准,接下来用代码证明一切
1、所有界面的预制体保存到Resources下方的文件夹,加载时使用Resource.Load("界面路径")
不要问为什么放在Resources文件夹,相信看到这里的人都懂,若是不懂建议从Unity基础治疗
2、把所有界面的名字和路径保存成配置文件,这里一般使用Json,你也可以使用其他配置文件,反正程序运行时你把程序的名字和放置路径拿到就行
{
"UI": [
{
"name": "HomePage",
"path": "UI/HomePage"
},
{
"name": "QJDL",
"path": "UI/QJDL"
},
{
"name": "QYZY",
"path": "UI/QYZY"
},
{
"name": "YWZY",
"path": "UI/YWZY"
},
{
"name": "ZHXX",
"path": "UI/ZHXX"
},
{
"name": "WDYY",
"path": "UI/WDYY"
},
{
"name": "DotInfo",
"path": "UI/DotInfo"
}
]
}
3、编写基类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//此项目只用到界面进入和退出,你可以根据自己的情况添加,只需要在界面的脚本实现相应的方法即可
public class BaseUI : MonoBehaviour
{
/// <summary>
/// UI界面进入
/// </summary>
public virtual void OnEnter()
{
}
/// <summary>
/// UI界面退出
/// </summary>
public virtual void OnExit()
{
}
}
4、编写管理类
4.1、所有界面的枚举
public enum E_UIType
{
HomePage,//首页
QJDL,
QYZY,
YWZY,
ZHXX,
WDYY,
DotInfo
}
4.2界面管理类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//界面管理类
public class UIManager : Singleton<UIManager>
{
private Transform uIParent;
//构造函数,第一次创建类时读取界面名字和路径
public UIManager()
{
LoadUIPath();
}
//程序界面加载到界面后的父对象
public Transform UIParent
{
get
{
if (uIParent == null)
{
uIParent = GameObject.Find("UI").transform;
}
return uIParent;
}
}
Dictionary<E_UIType, string> uIPathDic;//所有界面路径
Dictionary<E_UIType, BaseUI> uIObjectDic;//界面Base
Stack<BaseUI> uIStack;//界面进入的深度
//程序界面进入的入口
public void PushUI(E_UIType uIType)
{
if (uIStack == null)
uIStack = new Stack<BaseUI>();
if (uIStack.Count > 0)
{
BaseUI topUI = uIStack.Peek();
topUI.OnExit();
}
BaseUI loadUI = LoadUI(uIType);
loadUI.OnEnter();
uIStack.Push(loadUI);
returnBtn.Instance.RefreshReturn(uIType);
}
/// <summary>
/// 出栈,退出当前界面,加载上一个界面
/// </summary>
public void PopUI()
{
if (uIStack == null)
uIStack = new Stack<BaseUI>();
BaseUI exitUI = uIStack.Pop();
exitUI.OnExit();
if (uIStack.Count <= 0) return;
BaseUI loadUI = uIStack.Peek();
loadUI.OnEnter();
if (uIStack.Count <= 1)
returnBtn.Instance.RefreshReturn(E_UIType.HomePage);
}
/// <summary>
/// 加载UI界面时,先根据枚举查找所有已加载的界面里是否存在,若是存在直接返回,若是没有查找界面所有的路径,根据路径加载界面,然后返回
/// </summary>
/// <param name="uIType"></param>
/// <returns></returns>
BaseUI LoadUI(E_UIType uIType)
{
if (uIObjectDic == null)
uIObjectDic = new Dictionary<E_UIType, BaseUI>();
BaseUI loadUI = uIObjectDic.TryGet(uIType);
if (loadUI == null)
{
string path = uIPathDic.TryGet(uIType);
GameObject temp = Resources.Load<GameObject>(path);
GameObject uIObject = GameObject.Instantiate(temp, UIParent);
uIObjectDic.Add(uIType, uIObject.GetComponent<BaseUI>());
return uIObject.GetComponent<BaseUI>();
}
else
{
return loadUI;
}
}
/// <summary>
/// 读取界面路径,保存到界面路径字典中,这里只说框架,至于读取json问题,就不在这里说了
/// </summary>
void LoadUIPath()
{
TextAsset data = Resources.Load<TextAsset>("UI");
UI_ModeJson jsonObject = JsonUtility.FromJson<UI_ModeJson>(data.text);
foreach (UI_Mode item in jsonObject.UI)
{
if (uIPathDic == null)
uIPathDic = new Dictionary<E_UIType, string>();
uIPathDic.TryAdd(item.UIType, item.path);
}
}
}
5、程序使用时只需要提供一个入口即可
UIManager.Instance.PushUI(E_UIType.HomePage);
当然这个框架只是最简单的框架,也有一定局限性,此框架的局限性在于没办法显示层级界面,当进入的界面覆盖上一个界面的一部分,上一个界面也需要显示而不是隐藏时,就会暴露出来了,当然有问题就会有解决方案,把每个界面的属性保存,比如界面是否是一个窗口的一部分等一些枚举值记录,这就是优化之后的事情了。