无框架容易出现的问题
多个场景会反复出现相同的UI窗体,多个场景反复加载(复用)
各个UI脚本之间的传值,容易交错,耦合度高(UI之间不相互联系,通过消息传递)
要手工控制窗体中间的层级关系(使用栈结构保持控制当前所有需要显示的UI窗体)
多个UI窗体之间相互叠加,容易出现误操作(对当前窗体遮挡处理)
窗体自动加载管理
语言的国际化
UI框架核心原则
尽量让框架本身完成与具体业务无关的事务性工作,让开发人员只需要专注游戏的业务逻辑
开发最简版
1.窗体自动加载管理
2.缓存UI窗体
3.窗体生命周期管理
UI框架的核心类设计
1.BaseUIForms基础UI窗体
2.UIManager UI窗体管理
3.UIType窗体类型
4.SysDefine 系统定义类
链接:https://pan.baidu.com/s/1-PomcmeBh2Up1S3iHWTHqQ
提取码:41cf
创建一些文件夹把贴图素材导入MyAtlas
把脚本素材分别放到
然后把Log类先注释掉
定义一个窗口参数类
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: SysDefine.cs
*Author: why
*Version: 1.0
*UnityVersion:2017.2.2f1
*Date: 2019-05-10
*Description: UI框架核心参数
* 1.系统常量
* 2.全局性方法
* 3.系统枚举类型
* 4.委托定义
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
#region 系统枚举类型
///
/// UI窗体(位置)类型
///
public enum UIFormType
{
///
/// 普通窗体
///
Normal,
///
/// 固定窗体
///
Fixed,
///
/// 弹出窗体
///
PopUp,
}
///
/// UI窗体的显示类型
///
public enum UIFormShowMode
{
///
/// 普通
///
Normal,
///
/// 反向切换
/// //按照相反方向切换过去 原路弹回来
ReverseChange,
///
/// 隐藏其他
///
HideOther
}
///
/// UI窗体透明度类型
///
public enum UIFormLucenyType
{
///
/// 完全透明,不能穿透
///
Lucency,
///
/// 半透明,不能穿透
///
Translucence,
///
/// 低透明度,不能穿透
///
ImPenetrable,
///
/// 可以穿透
///
Pentrate
}
#endregion
public class SysDefine
{
}
然后定义一个 UI基类
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: BaseUI.cs
*Author: why
*Version: 1.0
*UnityVersion:2017.2.2f1
*Date: 2019-05-10
*Description: UI窗体父类
*定义UI窗体的父类
* 有四个生命周期
* 1.Display显示状态
* 2.Hiding隐藏状态
* 3.ReDisplay再显示状态
* 4.Freeze冻结状态 就是弹出窗体后面的窗体冻结
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//窗体类型
public class UIType
{
///
/// 是否清空"栈集合"
///
public bool isClearStack = false;
///
/// UI窗体(位置)类型
///
public UIFormType type = UIFormType.Normal;
///
///UI窗体显示类型
///
public UIFormShowMode mode = UIFormShowMode.Normal;
///
/// UI窗体透明度类型
///
public UIFormLucenyType lucenyType = UIFormLucenyType.Lucency;
}
public class BaseUI : MonoBehaviour
{
UIType currentUIType { get; set; } = new UIType();
#region 窗体的四种状态
///
/// 显示状态
///
public virtual void ActiveTrue()
{
gameObject.SetActive(true);
}
///
/// 隐藏状态
///
public virtual void ActiveFalse()
{
gameObject.SetActive(false);
}
///
/// 重新显示状态
///
public virtual void ReActiveTrue()
{
gameObject.SetActive(true);
}
///
/// 冻结状态
///
public virtual void Freeze()
{
gameObject.SetActive(true);
}
#endregion
#region 封装子类常用方法
///
/// 注册按钮事件
///
void RigisterBtnOnClick(string btnName,EventTriggerListener.VoidDelegate del)
{
Transform btn = UnityHelper.Find(gameObject.transform, btnName);
EventTriggerListener.Get(btn?.gameObject).onClick = del;
}
///
/// 打开UI窗体
///
///
void Open(string UIName)
{
}
///
/// 关闭UI窗体
///
void Close()
{
}
#endregion
}
还有一个UI管理类 先列举出字段
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: UIManager.cs
*Author: why
*Version: 1.0
*UnityVersion:2017.2.2f1
*Date: 2019-05-10
*Description: UI管理器
* 是整个UI框架的核心,用户程序通过本脚本,来实现框架绝大多数功能
* 原则
* 低耦合,高聚合
* 方法单一职责
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UIManager : MonoBehaviour {
///
/// UI窗体预设路径 <窗口名字,路径>
///
Dictionary UIPaths;
///
/// 缓存所有UI窗体
///
Dictionary cacheUIs;
///
/// 当前显示的UI窗体
///
Dictionary showUIs;
///
/// UI根节点
///
Transform traRoot;
///
/// 全屏幕显示的节点
///
Transform traNormal;
///
/// 固定显示的节点
///
Transform traFixed;
///
/// 弹出节点
///
Transform traPopUp;
///
/// UI脚本管理节点
///
Transform traUISprites;
private void Awake()
{
}
}
然后搭设场景
几个空节点还有UICamera
Canvans设置 为按相机照射 UIScaleMode调整为宽高比例缩放match一般是0.5或者按高度适配
相机处理设置为正交模式 照射层级只有UI 还有记得把相机往后拉一点点不然没有图片
然后再Nomal下创建这样的界面 记得定好锚点
在Resources保存为预制体 到时候动态加载
然后记得把UI相机的这个去掉
然后添加常量名字
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: SysDefine.cs
*Author: why
*Version: 1.0
*UnityVersion:2017.2.2f1
*Date: 2019-05-10
*Description: UI框架核心参数
* 1.系统常量
* 2.全局性方法
* 3.系统枚举类型
* 4.委托定义
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
#region 系统枚举类型
///
/// UI窗体(位置)类型
///
public enum UIFormType
{
///
/// 普通窗体
///
Normal,
///
/// 固定窗体
///
Fixed,
///
/// 弹出窗体
///
PopUp,
}
///
/// UI窗体的显示类型
///
public enum UIFormShowMode
{
///
/// 普通
///
Normal,
///
/// 反向切换
/// //按照相反方向切换过去 原路弹回来
ReverseChange,
///
/// 隐藏其他
///
HideOther
}
///
/// UI窗体透明度类型
///
public enum UIFormLucenyType
{
///
/// 完全透明,不能穿透
///
Lucency,
///
/// 半透明,不能穿透
///
Translucence,
///
/// 低透明度,不能穿透
///
ImPenetrable,
///
/// 可以穿透
///
Pentrate
}
#endregion
public class SysDefine
{
///
/// 路径常量
///
public const string canvasPath = "Canvas";
///
/// 标签常量
///
public const string canvasTag= "Canvas";
//全局性方法
//委托的定义
}
在UIManager添加UI创建方法
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: UIManager.cs
*Author: why
*Version: 1.0
*UnityVersion:2017.2.2f1
*Date: 2019-05-10
*Description: UI管理器
* 是整个UI框架的核心,用户程序通过本脚本,来实现框架绝大多数功能
* 原则
* 低耦合,高聚合
* 方法单一职责
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UIManager : MonoBehaviour
{
///
/// UI窗体预设路径 <窗口名字,路径>
///
Dictionary UIPaths = new Dictionary();
///
/// 缓存所有UI窗体
///
Dictionary cacheUIs = new Dictionary();
///
/// 当前显示的UI窗体
///
Dictionary showUIs = new Dictionary();
///
/// UI根节点
///
Transform traRoot;
///
/// 全屏幕显示的节点
///
Transform traNormal;
///
/// 固定显示的节点
///
Transform traFixed;
///
/// 弹出节点
///
Transform traPopUp;
///
/// UI脚本管理节点
///
Transform traUISprites;
///
/// 初始化核心数据,加载"UI窗体路径"到集合中
///
private void Awake()
{
InitRootCanvasLoading();
//得到UI根节点、全屏节点、固定节点、弹出节点
traRoot = GameObject.FindGameObjectWithTag(SysDefine.canvasTag).transform;
traNormal = traRoot.Find("Normal");
traFixed = traRoot.Find("Fixed");
traPopUp = traRoot.Find("PopUp");
traUISprites = traRoot.Find("ScriptsMgr");
//把本脚本作为"根UI窗体"的子节点 true世界坐标 false局部坐标
this.gameObject.transform.SetParent(traUISprites, false);
//"rootUI窗体"在场景转换时候,不允许被销毁
DontDestroyOnLoad(traRoot);
//初始化"UI窗体"路径信息
UIPaths?.Add("LoginUI", "UIPrefabs/LoginUI");
}
///
/// 打开/显示UI窗体
///
public void ShowUI(string UIName)
{
BaseUI baseUI;
if (string.IsNullOrEmpty(UIName))
return;
baseUI = LoadUIToCacheUIs(UIName);
if (baseUI == null)
return;
//根据不同的UI窗体的显示模式,分别作不同的加载处理
switch (baseUI.currentUIType.mode)
{
case UIFormShowMode.Normal:
break;
case UIFormShowMode.ReverseChange:
break;
case UIFormShowMode.HideOther:
break;
default:
break;
}
}
///
/// 初始化加载(rootUI窗体)Canvas预制体
///
private void InitRootCanvasLoading()
{
ResourcesMgr.GetInstance().LoadAsset(SysDefine.canvasPath, false);
}
#region 私有方法
///
/// 加载与判断指定的UI窗体的名字,加载到"所有UI窗体"缓存里
///
///
///
BaseUI LoadUIToCacheUIs(string UIName)
{
BaseUI baseUI;
//得到就返回 得不到返回null
cacheUIs.TryGetValue(UIName, out baseUI);
if (baseUI == null)
{
LoadUI(UIName);
}
return baseUI;
}
///
/// 根据不同位置信息,加载到root下不同的节点
///
BaseUI LoadUI(string UIName)
{
string uiPath;
GameObject UIPrefabs = null;
BaseUI baseUI = null;
UIPaths.TryGetValue(UIName, out uiPath);
if (!string.IsNullOrEmpty(uiPath))
{
UIPrefabs = ResourcesMgr.GetInstance().LoadAsset(uiPath, false);
}
if (traRoot != null && UIPrefabs != null)
{
baseUI = UIPrefabs.GetComponent();
if (baseUI == null)
{
Debug.Log($"baseUI==null,请确认窗口是否有BaseUI脚本,参数:{UIName}");
return null;
}
switch (baseUI.currentUIType.type)
{
case UIFormType.Normal:
UIPrefabs.transform.SetParent(traNormal, false);
break;
case UIFormType.Fixed:
UIPrefabs.transform.SetParent(traFixed, false);
break;
case UIFormType.PopUp:
UIPrefabs.transform.SetParent(traPopUp, false);
break;
}
UIPrefabs.SetActive(false);
cacheUIs.Add(UIName, baseUI);
return baseUI;
}
else
{
Debug.Log($"traRoot!=null Or UIPrefabs!=null Please Check 参数{UIName}");
}
Debug.Log($"出现不可预估的错误 参数{UIName}");
return null;
}
///
/// 把当前窗体加载到当前显示窗体集合中
///
void LoadUIToShowUIs(string UIName)
{
BaseUI baseUI;
BaseUI baseUIFormCache;
showUIs.TryGetValue(UIName, out baseUI);
if (baseUI == null)
return;
cacheUIs.TryGetValue(UIName, out baseUIFormCache);
if (baseUIFormCache != null)
{
showUIs.Add(UIName, baseUIFormCache);
baseUIFormCache.ActiveTrue();
}
}
#endregion
}
创建一个
挂给我们的LoginUI预制体
创一个空节点 挂上脚本
Text只有这个一句话 然后加载出来
因为没设置窗口激活所以是隐藏的
然后UI层级管理的话要用到栈 “先进后出”
Stack
类似于收盘子洗盘子 羽毛球筒放进去拿出来
还有类似于枪的弹夹
然后UIManager添加方法 有些判断写反了 又改了改
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: UIManager.cs
*Author: why
*Version: 1.0
*UnityVersion:2017.2.2f1
*Date: 2019-05-10
*Description: UI管理器
* 是整个UI框架的核心,用户程序通过本脚本,来实现框架绝大多数功能
* 原则
* 低耦合,高聚合
* 方法单一职责
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace UIFrameWork
{
public class UIManager : MonoBehaviour
{
public static UIManager instance;
///
/// UI窗体预设路径 <窗口名字,路径>
///
Dictionary UIPaths = new Dictionary();
///
/// 缓存所有UI窗体
///
Dictionary cacheUIs = new Dictionary();
///
/// 当前显示的UI窗体
///
Dictionary showUIs = new Dictionary();
///
/// 具备 "反向切换"窗体的管理
///
Stack staUIs = new Stack();
///
/// UI根节点
///
Transform traRoot;
///
/// 全屏幕显示的节点
///
Transform traNormal;
///
/// 固定显示的节点
///
Transform traFixed;
///
/// 弹出节点
///
Transform traPopUp;
///
/// UI脚本管理节点
///
Transform traUISprites;
///
/// 初始化核心数据,加载"UI窗体路径"到集合中
///
private void Awake()
{
instance = this;
InitRootCanvasLoading();
//得到UI根节点、全屏节点、固定节点、弹出节点
traRoot = GameObject.FindGameObjectWithTag(SysDefine.canvasTag).transform;
traNormal = UnityHelper.Find(traRoot, SysDefine.normalNode);
traFixed = UnityHelper.Find(traRoot, SysDefine.fixedNode);
traPopUp = UnityHelper.Find(traRoot, SysDefine.popUpNode);
traUISprites = UnityHelper.Find(traRoot, SysDefine.ScriptsMgrNode);
//把本脚本作为"根UI窗体"的子节点 true世界坐标 false局部坐标
this.gameObject.transform.SetParent(traUISprites, false);
//"rootUI窗体"在场景转换时候,不允许被销毁
DontDestroyOnLoad(traRoot);
//初始化"UI窗体"路径信息
UIPaths?.Add("LoginUI", "UIPrefabs/LoginUI");
UIPaths?.Add("SelectUI", "UIPrefabs/SelectUI");
}
///
/// 打开/显示UI窗体
///
public void ShowUI(string UIName)
{
BaseUI baseUI = null;
if (string.IsNullOrEmpty(UIName))
return;
baseUI = LoadUIToCacheUIs(UIName);
if (baseUI == null)
return;
//是否清空"栈集合"中得数据
if (baseUI.currentUIType.isClearStack)
{
if (!ClearStack())
Debug.Log($"栈中数据没有成功清空请检查参数{UIName}");
}
//根据不同的UI窗体的显示模式,分别作不同的加载处理
switch (baseUI.currentUIType.mode)
{
case UIFormShowMode.Normal:
LoadUIToShowUIs(UIName);
break;
case UIFormShowMode.ReverseChange:
PushUIToStack(UIName);
break;
case UIFormShowMode.HideOther:
EnterUIAndHideOther(UIName);
break;
}
}
///
/// 关闭(返回上一个)窗体
///
public void CloseUI(string UIName)
{
BaseUI baseUI;
//参数检查
if (string.IsNullOrEmpty(UIName))
return;
//所有UI窗体 没有记录直接返回
cacheUIs.TryGetValue(UIName, out baseUI);
if (baseUI == null)
return;
switch (baseUI.currentUIType.mode)
{
case UIFormShowMode.Normal:
ExitUI(UIName);
break;
case UIFormShowMode.ReverseChange:
PopUIToStack();
break;
case UIFormShowMode.HideOther:
ExitUIAndDisPlayOther(UIName);
break;
}
}
#region 显示"UI管理器"内部核心数据,测试使用
///
/// 显示所有UI窗体的数量
///
///
public int ShowCacheUIsCount()
{
return cacheUIs?.Count ?? 0;
}
///
/// 显示当前窗体的数量
///
///
public int ShowShowUIsCount()
{
return showUIs?.Count ?? 0;
}
///
/// 显示栈窗体的数量
///
///
public int ShowStaUIsCount()
{
return staUIs?.Count ?? 0;
}
#endregion
#region 私有方法
///
/// 初始化加载(rootUI窗体)Canvas预制体
///
private void InitRootCanvasLoading()
{
ResourcesMgr.GetInstance().LoadAsset(SysDefine.canvasPath, false);
}
///
/// 加载与判断指定的UI窗体的名字,加载到"所有UI窗体"缓存里
///
///
///
BaseUI LoadUIToCacheUIs(string UIName)
{
BaseUI baseUI;
//得到就返回 得不到返回null
cacheUIs.TryGetValue(UIName, out baseUI);
if (baseUI == null)
{
baseUI = LoadUI(UIName);
}
return baseUI;
}
///
/// 根据不同位置信息,加载到root下不同的节点
///
BaseUI LoadUI(string UIName)
{
string uiPath;
GameObject UIPrefabs = null;
BaseUI baseUI = null;
UIPaths.TryGetValue(UIName, out uiPath);
if (!string.IsNullOrEmpty(uiPath))
{
UIPrefabs = ResourcesMgr.GetInstance().LoadAsset(uiPath, false);
}
if (traRoot != null && UIPrefabs != null)
{
baseUI = UIPrefabs.GetComponent();
if (baseUI == null)
{
Debug.Log($"baseUI==null,请确认窗口是否有BaseUI脚本,参数:{UIName}");
return null;
}
switch (baseUI.currentUIType.type)
{
case UIFormType.Normal:
UIPrefabs.transform.SetParent(traNormal, false);
break;
case UIFormType.Fixed:
UIPrefabs.transform.SetParent(traFixed, false);
break;
case UIFormType.PopUp:
UIPrefabs.transform.SetParent(traPopUp, false);
break;
}
UIPrefabs.SetActive(false);
cacheUIs.Add(UIName, baseUI);
return baseUI;
}
else
{
Debug.Log($"traRoot!=null Or UIPrefabs!=null Please Check 参数{UIName}");
}
Debug.Log($"出现不可预估的错误 参数{UIName}");
return null;
}
///
/// 把当前窗体加载到当前显示窗体集合中
///
void LoadUIToShowUIs(string UIName)
{
BaseUI baseUI;
BaseUI baseUIFormCache;
showUIs.TryGetValue(UIName, out baseUI);
if (baseUI != null)
return;
cacheUIs.TryGetValue(UIName, out baseUIFormCache);
if (baseUIFormCache != null)
{
showUIs.Add(UIName, baseUIFormCache);
baseUIFormCache.ActiveTrue();
}
}
///
/// UI窗体入栈
///
void PushUIToStack(string UIName)
{
BaseUI baseUI;
//判断栈中是否有其他的窗体,有则冻结
if (staUIs.Count > 0)
{
BaseUI topUI = staUIs.Peek();
topUI.Freeze();
}
//判断UI所有窗体 是否有指定的UI窗体 有就处理
cacheUIs.TryGetValue(UIName, out baseUI);
if (baseUI != null)
{
baseUI.ActiveTrue();
//把指定UI窗体,入栈
staUIs.Push(baseUI);
}
else
Debug.Log($"baseUI==null,请确认窗口是否有BaseUI脚本,参数:{UIName}");
}
///
/// 退出指定UI窗体
///
///
void ExitUI(string UIName)
{
BaseUI baseUI;
//"正在显示集合"如果没有记录 则直接返回
showUIs.TryGetValue(UIName, out baseUI);
if (baseUI == null)
return;
//指定窗体,标记为隐藏状态,从正在显示集合中移除
baseUI.ActiveFalse();
showUIs.Remove(UIName);
}
///
/// 反向切换 窗体的出栈处理
///
void PopUIToStack()
{
BaseUI baseUI = staUIs.Pop();
baseUI.ActiveFalse();
if (staUIs.Count >= 2)
{
//下一个窗体重新显示
staUIs.Peek().ReActiveTrue();
}
}
///
/// 打开窗体 隐藏其他窗体
///
///
void EnterUIAndHideOther(string UIName)
{
BaseUI baseUI;
BaseUI baseUIFromAll;
if (string.IsNullOrEmpty(UIName))
return;
showUIs.TryGetValue(UIName, out baseUI);
if (baseUI != null)
return;
//把正在显示集合 栈集合都隐藏
foreach (var item in showUIs)
{
item.Value.ActiveFalse();
}
foreach (var item in staUIs)
{
item.ActiveFalse();
}
//把当前窗体加入到"正在显示窗体"集合中,且做显示处理
cacheUIs.TryGetValue(UIName, out baseUIFromAll);
if (baseUIFromAll != null)
{
showUIs.Add(UIName, baseUIFromAll);
baseUIFromAll.ActiveTrue();
}
}
///
/// 关闭窗体 显示其他窗体
///
///
void ExitUIAndDisPlayOther(string UIName)
{
BaseUI baseUI;
if (string.IsNullOrEmpty(UIName))
return;
showUIs.TryGetValue(UIName, out baseUI);
if (baseUI == null)
return;
//把当前窗口失活移除
baseUI.ActiveFalse();
showUIs.Remove(UIName);
//把正在显示集合 栈集合都激活
foreach (var item in showUIs)
{
item.Value.ReActiveTrue();
}
foreach (var item in staUIs)
{
item.ReActiveTrue();
}
}
///
/// 是否清空栈集合中数据
///
///
bool ClearStack()
{
if (staUIs != null && staUIs.Count >= 1)
{
staUIs.Clear();
return true;
}
return false;
}
#endregion
}
}
然后是把常量提取出来定义
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: SysDefine.cs
*Author: why
*Version: 1.0
*UnityVersion:2017.2.2f1
*Date: 2019-05-10
*Description: UI框架核心参数
* 1.系统常量
* 2.全局性方法
* 3.系统枚举类型
* 4.委托定义
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace UIFrameWork
{
#region 系统枚举类型
///
/// UI窗体(位置)类型
///
public enum UIFormType
{
///
/// 普通窗体
/// //一般是全屏窗体
Normal,
///
/// 固定窗体
/// //一般是固定不动的 某一方向的一组图标
Fixed,
///
/// 弹出窗体
///
PopUp,
}
///
/// UI窗体的显示类型
///
public enum UIFormShowMode
{
///
/// 普通
/// //同一层级叠加
Normal,
///
/// 反向切换
/// //按照相反方向切换过去 原路弹回来
ReverseChange,
///
/// 隐藏其他
/// //覆盖掉其他窗口
HideOther
}
///
/// UI窗体透明度类型
///
public enum UIFormLucenyType
{
///
/// 完全透明,不能穿透
///
Lucency,
///
/// 半透明,不能穿透
///
Translucence,
///
/// 低透明度,不能穿透
///
ImPenetrable,
///
/// 可以穿透
///
Pentrate
}
#endregion
public class SysDefine
{
// 路径常量
public const string canvasPath = "Canvas";
//标签常量
public const string canvasTag = "Canvas";
// 节点常量
public const string normalNode = "Normal";
public const string fixedNode = "Fixed";
public const string popUpNode = "PopUp";
public const string ScriptsMgrNode = "ScriptsMgr";
//摄像机层深的常量
//全局性方法
//委托的定义
}
}
我又把他的监听类 添加Transform也可以传递 语法糖改为C#6
/***
*
* Title: "SUIFW"UI框架项目
* 主题: 事件触发监听
* Description:
* 功能: 实现对于任何对象的监听处理。
* Date: 2017
* Version: 0.1版本
* Modify Recoder:
*
*
*/
using UnityEngine;
using UnityEngine.EventSystems;
namespace UIFrameWork
{
public class EventTriggerListener : UnityEngine.EventSystems.EventTrigger
{
public delegate void VoidDelegate(GameObject go);
public VoidDelegate onClick;
public VoidDelegate onDown;
public VoidDelegate onEnter;
public VoidDelegate onExit;
public VoidDelegate onUp;
public VoidDelegate onSelect;
public VoidDelegate onUpdateSelect;
///
/// 得到“监听器”组件
///
/// 监听的游戏对象
///
/// 监听器
///
public static EventTriggerListener Get(GameObject go)
{
EventTriggerListener lister = go?.GetComponent();
if (lister == null)
{
lister = go.AddComponent();
}
return lister;
}
public static EventTriggerListener Get(Transform go)
{
EventTriggerListener lister = go?.GetComponent();
if (lister == null)
{
lister = go.gameObject.AddComponent();
}
return lister;
}
public override void OnPointerClick(PointerEventData eventData)
{
onClick?.Invoke(gameObject);
}
public override void OnPointerDown(PointerEventData eventData)
{
onDown?.Invoke(gameObject);
}
public override void OnPointerEnter(PointerEventData eventData)
{
onEnter?.Invoke(gameObject);
}
public override void OnPointerExit(PointerEventData eventData)
{
onExit?.Invoke(gameObject);
}
public override void OnPointerUp(PointerEventData eventData)
{
onUp?.Invoke(gameObject);
}
public override void OnSelect(BaseEventData eventBaseData)
{
onSelect?.Invoke(gameObject);
}
public override void OnUpdateSelected(BaseEventData eventBaseData)
{
onUpdateSelect?.Invoke(gameObject);
}
}//Class_end
}
UI基类封装常用方法
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: BaseUI.cs
*Author: why
*Version: 1.0
*UnityVersion:2017.2.2f1
*Date: 2019-05-10
*Description: UI窗体父类
*定义UI窗体的父类
* 有四个生命周期
* 1.Display显示状态
* 2.Hiding隐藏状态
* 3.ReDisplay再显示状态
* 4.Freeze冻结状态 就是弹出窗体后面的窗体冻结
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace UIFrameWork
{
//窗体类型
public class UIType
{
///
/// 是否清空"栈集合" 反向切换
///
public bool isClearStack = false;
///
/// UI窗体(位置)类型
///
public UIFormType type = UIFormType.Normal;
///
///UI窗体显示类型
///
public UIFormShowMode mode = UIFormShowMode.Normal;
///
/// UI窗体透明度类型
///
public UIFormLucenyType lucenyType = UIFormLucenyType.Lucency;
}
public class BaseUI : MonoBehaviour
{
public UIType currentUIType { get; set; } = new UIType();
#region 窗体的四种状态
///
/// 显示状态
///
public virtual void ActiveTrue()
{
gameObject.SetActive(true);
}
///
/// 隐藏状态
///
public virtual void ActiveFalse()
{
gameObject.SetActive(false);
}
///
/// 重新显示状态
///
public virtual void ReActiveTrue()
{
gameObject.SetActive(true);
}
///
/// 冻结状态
///
public virtual void Freeze()
{
gameObject.SetActive(true);
}
#endregion
#region 封装子类常用方法
///
/// 注册按钮事件
///
protected void RigisterBtnOnClick(string btnName, EventTriggerListener.VoidDelegate del)
{
Transform btn = UnityHelper.Find(gameObject.transform, btnName);
EventTriggerListener.Get(btn?.gameObject).onClick = del;
}
///
/// 打开UI窗体
///
///
protected void OpenUI(string UIName)
{
UIManager.instance.ShowUI(UIName);
}
///
/// 关闭UI窗体
///
protected void CloseUI()
{
string UIName;
//int intPos = -1;
//命名空间+类名
UIName = GetType().ToString();
//查询第一次出现在这在第几位
//intPos = UIName.IndexOf('.');
//if (intPos != -1)
//{
// UIName = UIName.Substring(intPos + 1);
//}
UIManager.instance.CloseUI(UIName);
}
#endregion
}
}
提供一个方法类Find Add的封装
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: UnityHelper.cs
*Author: why
*Version: 1.0
*UnityVersion:2017.2.2f1
*Date: 2019-05-10
*Description: Unity帮助脚本
* 提供程序用户一些常用功能方法实现,方便程序员快速开发
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace UIFrameWork
{
public class UnityHelper
{
///
/// 递归查找子结点
///
///
public static Transform Find(Transform parent, string childName)
{
Transform child = null;
child = parent.transform.Find(childName);
if (child == null)
{
//直接是所有子物体对象
foreach (Transform item in parent)
{
child = Find(item, childName);
if (child != null)
return child;
}
}
return child;
}
///
/// 获取子节点对象的脚本 限定范围游戏对象的组件
///
///
///
///
///
public static T GetComponent(Transform parent, string childName) where T : Component
{
Transform child = null;
child = Find(parent, childName);
return child?.gameObject.GetComponent();
}
///
/// 给子节点添加脚本
///
///
///
///
///
public static T AddComponent(Transform parent, string childName) where T : Component
{
Transform child = null;
child = Find(parent, childName);
//如果有相同的脚本,则先删除
T[] componentScriptsArray = child.GetComponents();
for (int i = 0; i < componentScriptsArray.Length; i++)
{
GameObject.Destroy(componentScriptsArray?[i]);
}
return child?.gameObject.AddComponent();
}
///
/// 给子节点设置父对象
///
///
///
public static void SetParent(Transform parent, Transform child)
{
//如果为真,则修改父级相对位置、比例和旋转,以便
//对象保持与以前相同的世界空间位置、旋转和缩放。
child.SetParent(parent, false);
child.localPosition = Vector3.zero;
child.localScale = Vector3.one;
child.localEulerAngles = Vector3.zero;
}
}
}
然后拿去测试
这里定义一些窗口的常量定义
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: ProConst.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-12
*Description: 项目中常量定义
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ProConst
{
//常量定义 UI窗体名
public const string LoginUI = "LoginUI";
public const string SelectUI = "SelectUI";
}
登录逻辑
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: LoginUI.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-11
*Description: 登录窗体
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UIFrameWork;
public class LoginUI : BaseUI
{
public void Awake()
{
//定义窗口性质 (默认数值)
currentUIType.type = UIFormType.Normal;
currentUIType.mode = UIFormShowMode.Normal;
currentUIType.lucenyType = UIFormLucenyType.Lucency;
//注册按钮
RigisterBtnOnClick("btnLogin", LogonSys);
}
public void LogonSys(GameObject go)
{
//前台或者后台检查用户名称与密码
//如果成功,则登录下一个窗口
OpenUI(ProConst.SelectUI);
}
}
人物选择界面逻辑
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: SelectUI.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-11
*Description: 选择英雄窗体
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UIFrameWork;
public class SelectUI :BaseUI
{
private void Awake()
{
//定义窗口性质 (默认数值)
currentUIType.mode = UIFormShowMode.HideOther;
//进入主城
RigisterBtnOnClick("BtnConfirm", go =>Debug.Log("进入主城"));
//返回方法
RigisterBtnOnClick("BtnClose", go => CloseUI());
}
// Update is called once per frame
void Update()
{
}
}
拖一个选择界面
主城还没做 只有个Deg提示
然后可以来回切换
脚本这么放