框架整体介绍:
1、UIManager中加载所有UI,存到列表中,使用时实例化到场景,根据类型分层
2、各面板继承BasePanel,自己进行生命周期管理
细节整理:
1、面板属性定义
/*******************************************************************************
* 版本声明:v1.0.0
* 类 名 称:TypeDefine
* 创建日期:2019-12-03 11:17:00
* 作者名称:末零
* 功能描述:定义UI面板属性的枚举
******************************************************************************/
namespace LastZero
{
/// <summary>
/// 面板类型
/// </summary>
public enum PanelType
{
Normal, //普通UI
Fixed, //固定窗口(例:Top)
PopUp //弹出
}
/// <summary>
/// 显示类型
/// </summary>
public enum PanelShowType
{
DoNothing, //无操作
HideOther, //关闭其他界面
SelfControl, //不受HideOther影响
DoBack //返回功能
}
/// <summary>
/// 遮罩类型
/// </summary>
public enum PanelMaskType
{
None, //显示该界面不包含碰撞背景
NoBg, //碰撞透明背景
WithBg, //碰撞非透明背景
}
}
2、面板属性设置
/*******************************************************************************
* 版本声明:v1.0.0
* 类 名 称:UIType
* 创建日期:2019-12-03 11:25:49
* 作者名称:末零
* 功能描述:面板属性
******************************************************************************/
using UnityEngine;
namespace LastZero
{
/// <summary>
/// 面板属性
/// </summary>
public class UIType : MonoBehaviour
{
/// <summary>
/// UI类型
/// </summary>
public PanelType panelType = PanelType.Normal;
/// <summary>
/// UI显示类型
/// </summary>
public PanelShowType showType = PanelShowType.DoNothing;
/// <summary>
/// UI遮罩类型
/// </summary>
public PanelMaskType maskType = PanelMaskType.None;
/// <summary>
/// 设置
/// </summary>
/// <param name="pt">UI类型</param>
/// <param name="pst">UI显示类型</param>
/// <param name="pmt">UI遮罩类型</param>
public void SetType(PanelType pt, PanelShowType pst, PanelMaskType pmt)
{
panelType = pt;
showType = pst;
maskType = pmt;
}
}
}
3、系统定义(路径定义为例)
/*******************************************************************************
* 版本声明:v1.0.0
* 类 名 称:PathDefine
* 创建日期:2019-12-03 11:30:02
* 作者名称:末零
* 功能描述:路径常量定义
******************************************************************************/
namespace LastZero
{
/// <summary>
/// 路径常量定义
/// </summary>
public class PathDefine
{
public const string canvasPath = "UIPrefabs/Canvas/MainCanvas";//Canvas路径
public const string panelPath = "UIPrefabs/Panels";//面板预制体路径
public const string maskPanelPath = "PopUp/MaskPanel";//遮罩面板Hierarchy路径
}
}
4、记录器
/*******************************************************************************
* 版本声明:v1.0.0
* 类 名 称:Recorder
* 创建日期:2019-12-05 16:47:01
* 作者名称:末零
* 功能描述:记录器
******************************************************************************/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace LastZero
{
/// <summary>
/// 记录器
/// </summary>
public class Recorder
{
}
}
下面重点说下基类和UI管理类:
5、BasePanel
首先自己定义面板属性,
生命周期:
(1)Init,相当于Awake,在面板被实例化的时候执行一次
(2)OnShow、OnHide,相当于OnEnable和OnDisable
没有做其它生命周期
接下来呢,面板自身定义Show和Hide方法,此处采用Scale控制
对于Show,特殊说明一下,因为第一次使用面板时,需要实例化,所以此处需有判断,若未实例化,则实例化,删除列表中的面板,加入实例化出的新面板,显示时通过属性判断,设置层,设置类型。对于Hide呢,主要需要判断是否需要关闭Mask。
代码如下:
/*******************************************************************************
* 版本声明:v1.0.0
* 类 名 称:BasePanel
* 创建日期:2019-12-03 11:14:13
* 作者名称:末零
* 功能描述:面板基类
******************************************************************************/
using UnityEngine;
using UnityEngine.UI;
namespace LastZero
{
/// <summary>
/// 面板基类
/// </summary>
public class BasePanel : MonoBehaviour
{
#region 面板属性
/// <summary>
/// 面板属性
/// </summary>
private UIType uiType = new UIType();
/// <summary>
/// 属性(程序集)_当前Panel类型
/// </summary>
internal UIType CurrentUIType
{
set { uiType = value; }
get { return uiType; }
}
#endregion
#region 面板显示
/// <summary>
/// 面板
/// </summary>
private BasePanel panel;
/// <summary>
/// 显示面板
/// </summary>
public BasePanel Show()
{
panel = this;
if (transform.parent == null)
{
panel = InstantiatePanel();
}
else
{
SetShowType(this);
}
transform.localScale = Vector3.one;
//如果是弹出面板 设置遮罩
if (panel.uiType.panelType == PanelType.PopUp)
SetMask();
OnShow();
return panel;
}
/// <summary>
/// 实例化面板
/// </summary>
public BasePanel InstantiatePanel()
{
BasePanel newPanel = Instantiate(this);
newPanel.Init();
UIManager.GetInstance().Panels.Remove(this);
UIManager.GetInstance().Panels.Add(newPanel);
newPanel.transform.SetParent(UIManager.GetInstance().GetCanvas().Find(newPanel.CurrentUIType.panelType.ToString()), false);
newPanel.gameObject.SetActive(true);
SetShowType(newPanel);
return newPanel;
}
/// <summary>
/// 初始化(相当于Awake)
/// </summary>
protected virtual void Init()
{
SetPanelType();
}
/// <summary>
/// 设置面板类型
/// </summary>
protected virtual void SetPanelType(){ }
/// <summary>
/// 设置显示类型
/// </summary>
/// <param name="panel"></param>
private void SetShowType(BasePanel panel)
{
if (panel.CurrentUIType.showType == PanelShowType.HideOther)
{
for (int i = 0; i < UIManager.GetInstance().Panels.Count; i++)
{
if (UIManager.GetInstance().Panels[i].transform.parent != null && UIManager.GetInstance().Panels[i].CurrentUIType.showType != PanelShowType.SelfControl)
UIManager.GetInstance().Panels[i].Hide();
}
}
else if (panel.CurrentUIType.showType == PanelShowType.DoBack)
{
UIManager.GetInstance().panelsDoBack.Push(panel);
}
}
/// <summary>
/// 设置遮罩
/// </summary>
private void SetMask()
{
Image mask = UIManager.GetInstance().GetCanvas().Find(PathDefine.maskPanelPath).GetComponent<Image>();
switch (panel.uiType.maskType)
{
case PanelMaskType.None:
mask.gameObject.SetActive(false);
break;
case PanelMaskType.NoBg:
mask.gameObject.SetActive(true);
mask.color = new Color(1, 1, 1, 0);
break;
case PanelMaskType.WithBg:
mask.gameObject.SetActive(true);
mask.color = new Color(1, 1, 1, 1);
break;
}
}
/// <summary>
/// 显示时要执行的方法
/// </summary>
protected virtual void OnShow() { }
#endregion
#region 面板隐藏
/// <summary>
/// 隐藏面板
/// </summary>
public void Hide()
{
transform.localScale = Vector3.zero;
if (uiType.panelType == PanelType.PopUp)
UIManager.GetInstance().GetCanvas().Find(PathDefine.maskPanelPath).gameObject.SetActive(false);
OnHide();
}
/// <summary>
/// 隐藏时要执行的方法
/// </summary>
protected virtual void OnHide() { }
#endregion
#region 获取面板
/// <summary>
/// 获取组件
/// </summary>
/// <typeparam name="T">组件</typeparam>
/// <param name="path">路径</param>
/// <returns></returns>
public T GetMyComponent<T>(string path)
{
return transform.Find(path).GetComponent<T>();
}
#endregion
}
}
6、UIManager
首先,加载Canvas,加载所有面板存储,在管理类中进行界面显隐(此处做特殊说明,面板通过类来存储,显示隐藏时由泛型查找),另外界面的回退也再次通过栈来控制。
/*******************************************************************************
* 版本声明:v1.0.0
* 类 名 称:UIManger
* 创建日期:2019-12-03 13:25:17
* 作者名称:末零
* 功能描述:UI管理类
******************************************************************************/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace LastZero
{
/// <summary>
/// UI管理类
/// </summary>
public class UIManager
{
/// <summary>
/// 构造
/// </summary>
private UIManager()
{
InitRootCanvasLoading();
AddAllPanel(PathDefine.panelPath);
}
#region 单例
private static UIManager _instance = null;
/// <summary>
/// 单例
/// </summary>
/// <returns></returns>
public static UIManager GetInstance()
{
if (_instance == null)
{
_instance = new UIManager();
}
return _instance;
}
#endregion
#region Canvas、Panels
/// <summary>
/// Canvas
/// </summary>
private Transform canvas = null;
/// <summary>
/// 初始化加载Canvas预设
/// </summary>
private void InitRootCanvasLoading()
{
canvas = Object.Instantiate(Resources.Load<Transform>(PathDefine.canvasPath));
}
/// <summary>
/// 获取Canvas
/// </summary>
/// <returns>canvas</returns>
public Transform GetCanvas()
{
if (canvas == null)
canvas = Object.FindObjectOfType<MainCanvas>().transform;
return canvas;
}
/// <summary>
/// 面板列表
/// </summary>
//private List<BasePanel> panelsNotInstantiate = new List<BasePanel>();
private List<BasePanel> panels = new List<BasePanel>();
/// <summary>
/// 面板访问器
/// </summary>
public List<BasePanel> Panels
{
get { return panels; }
}
/// <summary>
/// 添加面板到列表
/// </summary>
/// <param name="panel">面板</param>
public void AddAllPanel(string path)
{
panels.AddRange(Resources.LoadAll<BasePanel>(path));
}
/// <summary>
/// 有返回功能的面板
/// </summary>
public Stack<BasePanel> panelsDoBack = new Stack<BasePanel>();
/// <summary>
/// 返回上一个页面
/// </summary>
public void DoBack()
{
panelsDoBack.Pop().Hide();
panelsDoBack.Peek().Show();
}
#endregion
#region 面板显隐
/// <summary>
/// 显示面板
/// </summary>
/// <typeparam name="T">面板</typeparam>
/// <returns>PanelBase</returns>
public T ShowPanel<T>() where T : BasePanel
{
BasePanel panel = panels.Find(p => p is T);
return ShowPanel(panel) as T;
}
/// <summary>
/// 显示面板
/// </summary>
/// <param name="panel">面板</param>
/// <returns>PanelBase</returns>
private BasePanel ShowPanel(BasePanel panel)
{
if (panel == null)
return null;
return panel.Show();
}
/// <summary>
/// 隐藏面板
/// </summary>
/// <typeparam name="T">面板</typeparam>
/// <returns>PanelBase</returns>
public T HidePanel<T>() where T : BasePanel
{
BasePanel panel = panels.Find(p => p is T);
HidePanel(panel);
return panel as T;
}
/// <summary>
/// 隐藏面板
/// </summary>
/// <param name="panel">面板</param>
/// <returns>PanelBase</returns>
private static void HidePanel(BasePanel panel)
{
if (panel == null)
return;
panel.Hide();
}
/// <summary>
/// 获取面板
/// </summary>
/// <typeparam name="T">面板</typeparam>
/// <returns>PanelBase</returns>
public T GetPanel<T>() where T : BasePanel
{
BasePanel panel = panels.Find(p => p is T);
return panel as T;
}
#endregion
}
}
至此,框架基本就搭建完了,但是 ,涉及到UI界面与3维物体的交互,不打算采用消息传递机制,后面会继续研究,也会有其他方面的扩展。