Unity UI框架的搭建
为什么要使用UI框架呢?
在我刚使用Unity开发UI界面时,根本没想过用什么UI框架,都是想到要什么界面就通过UGUI拖动什么界面。如果需要实现交互功能,就会绑定对应的监听函数,这样的做法固然是非常的简单直接,但是也会留下一定的弊端。
当你的项目不在简单时,UI界面和控件越来越多时,你有时候会找不到哪个对象和哪个对象关联,要是团队合作的话,别人找你的UI接口更是找半天,耦合度非常之高,经常会牵一发而动全身,代码混乱,所以这个时候有一个好的UI框架,会更便于我们整合和使用UI。
设计UI框架的要点
1.设计一个UI的基类BaseUI,里面有UI的一些基本属性,显示方式等,所有UI的脚本都继承它
2.设计一个管理UI的框架UIManager,为UI的显示、销毁、切换等提供方法接口,并把该脚本设为单例模式,每个UI间互不干扰
3.UI间通信、UI和游戏层的通信通过一个消息分发的脚本去实现,即利用观察者模式,都通过MessageCenter来联系
部分伪代码:
建立一个定义UI类型的脚本
//窗体IDpublic enum E_UiId{MainUI,//主界面PlayUI,//游戏界面}//窗体的层级public enum E_UIRootType{KeepAbove,// 保持在最前方的窗体Normal// 普通窗体}//窗体的显示方式public enum E_ShowUIMode{// 窗体显示出来的时候,不会去隐藏任何窗体DoNothing,// 窗体显示出来的时候,会隐藏掉所有的普通窗体,但是不会隐藏保持在最前方的窗体HideOther,// 窗体显示出来的时候,会隐藏所有的窗体,不管是普通的还是保持在最前方的HideAll}// 消息类型public enum E_MessageType{ImageChange,// 图片更换textChange,// 文字更换RewardChange,// 奖励更换WeaponChange,// 武器更换BulletTips// 弹药提示}public class GameDefine{// 导入UI预制体文件(名字,路径)public static Dictionary<E_UiId, string> dicPath = new Dictionary<E_UiId, string>(){{ E_UiId.MainUI,"UIPrefab/"+"MainPanel"},{ E_UiId.PlayUI,"UIPrefab/"+"PlayPanel"}};// 自动挂载UI脚本public static Type GetUIScriptType(E_UiId uiId){Type scriptType = null;switch (uiId){case E_UiId.NullUI:break;case E_UiId.MainUI:scriptType = typeof(MainUI);break;case E_UiId.PlayUI:scriptType = typeof(PlayUI);break;default:break;}return scriptType;}}
定义UI基类
//窗体类型public class UIType{//显示方式public E_ShowUIMode showMode = E_ShowUIMode.HideOther;//父节点的类型public E_UIRootType uiRootType = E_UIRootType.Normal;}public class BaseUI : MonoBehaviour{//窗体类型public UIType uiType;//缓存窗体的RectTransform组件protected RectTransform thisTrans;//当前窗体的IDprotected E_UiId uiId = E_UiId.NullUI;//上一个窗体的IDprotected E_UiId beforeUiId = E_UiId.NullUI;//获取当前窗体的IDpublic E_UiId GetUiId{get{return uiId;}//为什么没有set?//因为每个窗体的ID都是固定的,不能被外界随意修改,外界只能获取它的值//只有在子类才能对该窗体的ID进行赋值或修改//set//{// uiId = value;//}}protected virtual void Awake(){if (uiType == null){uiType = new UIType();}thisTrans = this.GetComponent<RectTransform>();InitUiOnAwake();InitDataOnAwake();}//用于判断窗体显示出来的时候,是否需要去隐藏其他窗体public bool IsHideOtherUI(){if (this.uiType.showMode == E_ShowUIMode.DoNothing){return false;//不需要隐藏其他窗体}else{//需要去处理隐藏其他窗体的逻辑return true;// E_ShowUIMode.HideOther与 E_ShowUIMode.HideAll}}//初始化界面元素protected virtual void InitUiOnAwake(){}//初始化数据protected virtual void InitDataOnAwake(){}protected virtual void Start(){InitOnStart();}//初始化相关逻辑protected virtual void InitOnStart(){}//窗体的显示public virtual void ShowUI(){this.gameObject.SetActive(true);}//窗体额隐藏public virtual void HideUI(Del_AfterHideUI del = null){this.gameObject.SetActive(false);if (del != null){del();}}
定义UIManager框架
//这里我把单例模式写成了一个基类UnitySingleton并继承
public class UIManager : UnitySingleton<UIManager>
{//缓存所有打开过的窗体private Dictionary<E_UiId, BaseUI> dicAllUI;//缓存正在显示的窗体private Dictionary<E_UiId, BaseUI> dicShowUI;//缓存最近显示出来的窗体private BaseUI currentUI = null;//缓存上一个窗体// private BaseUI beforeUI = null;private E_UiId beforeUiId = E_UiId.NullUI;//缓存画布private Transform canvas;//缓存保持在最前方的窗体的父节点private Transform keepAboveUIRoot;//缓存普通窗体的父节点private Transform normalUIRoot;private void Awake(){//Test.Instance.Show();dicAllUI = new Dictionary<E_UiId, BaseUI>();dicShowUI = new Dictionary<E_UiId, BaseUI>();InitUIManager();}//初始化UI管理类private void InitUIManager(){canvas = this.transform.parent;//设置画布在场景切换的时候不被销毁,因为整个游戏共用唯一的一个画布DontDestroyOnLoad(canvas);if (keepAboveUIRoot==null){keepAboveUIRoot = GameTool.FindTheChild(canvas.gameObject, "KeepAboveUIRoot");}if (normalUIRoot==null){normalUIRoot= GameTool.FindTheChild(canvas.gameObject, "NormalUIRoot");}}//供外界调用,销毁窗体public void DestroyUI(E_UiId uiId){if (dicAllUI.ContainsKey(uiId)){//存在该窗体,去销毁Destroy( dicAllUI[uiId].gameObject);dicAllUI.Remove(uiId);}}//供外界调用的,显示窗体的方法public BaseUI ShowUI(E_UiId uiId,bool isSaveBeforeUiId=true){if (uiId == E_UiId.NullUI){uiId = E_UiId.MainUI;}BaseUI baseUI=JudgeShowUI(uiId);if (baseUI!=null){baseUI.ShowUI();}if (isSaveBeforeUiId){baseUI.BeforeUiId = beforeUiId;}return baseUI;}//供外界调用,反向切换窗体的方法public void ReturnBeforeUI(E_UiId uiId){ShowUI(uiId,false);}//供外界调用的,隐藏单个窗体的方法public void HideSingleUI(E_UiId uiId, Del_AfterHideUI del=null){if (!dicShowUI.ContainsKey(uiId)){return; }dicShowUI[uiId].HideUI(del);dicShowUI.Remove(uiId);}private BaseUI JudgeShowUI(E_UiId uiId){//判断将要显示的窗体是否已经正在显示了if (dicShowUI.ContainsKey(uiId)){//如果已经正在显示了,就不需要处理其他逻辑了return null;}//判断窗体是否有加载过BaseUI baseUI = GetBaseUI(uiId);if (baseUI == null){//说明这个窗体没显示过(没有加载过),要去动态加载string path = GameDefine.dicPath[uiId];GameObject theUI = Resources.Load<GameObject>(path);if (theUI != null){//把该窗体生成出来GameObject willShowUI = Instantiate(theUI);//窗体生成出来后,要确保有挂对应的UI脚本baseUI = willShowUI.GetComponent<BaseUI>();if (baseUI == null){//说明生成出来的这个窗体上面没有挂载对应的UI脚本//那么就需要给这个窗体自动添加对应的脚本Type type = GameDefine.GetUIScriptType(uiId);baseUI = willShowUI.AddComponent(type) as BaseUI;}//判断这个窗体是属于哪个父节点的Transform uiRoot = GetTheUIRoot(baseUI);GameTool.AddChildToParent(uiRoot, willShowUI.transform);willShowUI.GetComponent<RectTransform>().sizeDelta = Vector2.zero;//这个窗体是第一次加载显示出来的,那么就需要缓存起来dicAllUI.Add(uiId, baseUI);}else{Debug.LogError("指定路径下面找不到对应的预制体");}}UpdateDicShowUIAndHideUI(baseUI);return baseUI;}//更新缓存正在显示的窗体的字典并且隐藏对应的窗体private void UpdateDicShowUIAndHideUI(BaseUI baseUI){//判断是否需要隐藏其他窗体if (baseUI.IsHideOtherUI()){//如果返回值为true, E_ShowUIMode.HideOther与 E_ShowUIMode.HideAll//需要隐藏其他窗体if (dicShowUI.Count>0){//有窗体正在显示,就要隐藏对应的窗体if (baseUI.uiType.showMode == E_ShowUIMode.HideOther){HideAllUI(false, baseUI);}else{HideAllUI(true, baseUI);}}}//更新缓存正在显示的窗体的字典dicShowUI.Add(baseUI.GetUiId, baseUI);}public void HideAllUI(bool isHideAboveUI,BaseUI baseUI){ if (isHideAboveUI){//1、隐藏所有的窗体,不管是普通窗体还是保持在最前方的窗体,都需要全部隐藏foreach (KeyValuePair<E_UiId,BaseUI> uiItem in dicShowUI){uiItem.Value.HideUI(); }dicShowUI.Clear();}else{//2、隐藏所有的窗体,但是不包含保持在最前方的窗体//缓存所有被隐藏的窗体List<E_UiId> list = new List<E_UiId>();foreach (KeyValuePair<E_UiId, BaseUI> uiItem in dicShowUI){//如果不是保持在最前方的窗体if (uiItem.Value.uiType.uiRootType != E_UIRootType.KeepAbove){uiItem.Value.HideUI();//存储上一个窗体的IDbeforeUiId = uiItem.Key;// baseUI.BeforeUiId= uiItem.Key;list.Add(uiItem.Key);}}for (int i = 0; i < list.Count; i++){dicShowUI.Remove(list[i]);}}}//判断窗体的父物体private Transform GetTheUIRoot(BaseUI baseUI){if (baseUI.uiType.uiRootType == E_UIRootType.KeepAbove){return keepAboveUIRoot;}else{return normalUIRoot;}}private BaseUI GetBaseUI(E_UiId UiId){if (dicAllUI.ContainsKey(UiId)){return dicAllUI[UiId];}else{return null;}}
}
定义通讯中心MessageCenter
public class MessageCenter : MonoBehaviour
{public delegate void CallBack(object obj);//一个用来存放所有监听的字典<消息类型,监听到消息后所要处理的逻辑>public static Dictionary<E_MessageType, CallBack> dicMessageType = new Dictionary<E_MessageType, CallBack>();//添加监听public static void AddMessageListener(E_MessageType messageType, CallBack callBack){if (!dicMessageType.ContainsKey(messageType)){dicMessageType.Add(messageType, null);}dicMessageType[messageType] += callBack;}//取消监听public static void RemoveListener(E_MessageType messageType, CallBack callBack){if (dicMessageType.ContainsKey(messageType)){dicMessageType[messageType] -= callBack;}}//取消所有的监听public static void RemoveAllMessage(){dicMessageType.Clear();}//广播消息public static void SendMessage(E_MessageType messageType, object obj = null){CallBack callBack;if (dicMessageType.TryGetValue(messageType, out callBack)){if (callBack != null){callBack(obj);}}}
}
以上就是一个基本的UI框架了,接下来只要自己去创建对应的UI界面并处理好继承问题和初始化一些基础的UI属性即可,其他的一些UI框架其实也万变不离其中,主要目的还是解耦,便于处理,如果有好用的框架欢迎私信或者底下留言我,大家一起分享!
链接: 看到一位已经转行做厨师的兄弟有感而发
Unity UI框架的搭建相关推荐
- unity ui框架_[教程汇总+持续更新]Unity从入门到入坟——收藏这一篇就够了
----------------塔防(更新中),作者重写了基础篇(下方目录为:1.1(新) 基础)目前还在持续连载了5篇,因为不多我们更新完就能追到原作者的进度了------------------- ...
- Android QQ空间(Apad)项目总结(三)---应用UI框架的搭建!!!
大家好,今天是元旦节了,祝大家节日快乐!今天给大家分享的是Apad Qzone的UI框架,我们首先看下交互图如下: 图1:交互效果图. 从上图可以看出,整个应用其实UI框架相对比较简单,可以分为俩部分 ...
- (转)Android QQ空间(Apad)项目总结(三)---应用UI框架的搭建!!!
今天给大家分享的是Apad Qzone的UI框架,我们首先看下交互图如下: 图1:交互效果图. 从上图可以看出,整个应用其实UI框架相对比较简单,可以分为俩部分,左侧导航栏区域,右侧显示内容区域.当我 ...
- unity ui框架_用unity制作简单的太空游戏(2)-简单炮台
多铆蒸刚,炮塔至大! 亿万星辰,亿万炮塔! 多铆蒸刚,炮塔至上! 亿万炮塔,亿万荣光! (PS:我没有咕咕咕,就是比较惨,一口气出了半个月的差,人瘦了,也黑了,心塞塞--赶紧写个文章压压惊--) 这一 ...
- Unity UI 框架
开源地址: GitHub - NRatel/NRFramework.UI: 基于 Unity UGUI 的 UI 开发框架基于 Unity UGUI 的 UI 开发框架. Contribute to ...
- 微信小程序 - Vant weapp UI 框架环境搭建详细教程(Window)
前言 强烈推荐您打开 官方文档,对照着本教程一起对比搭建坏境. 自从 2022 年开始,小程序做了很多改变和升级, 导致网上很多搭建教程文章的教程失效了,本文来做最新的教程. 第一步 为了更贴合新手, ...
- Unity UI框架
窗口管理 初始化 在场景中挂载一个脚本,用于创建初始界面 using UnityEngine;//创建开始界面 public class CreateStartPanel : MonoBehaviou ...
- Unity UI框架详细理解--场景管理
SceneState类:存放场景状态 OnEnter方法:负责实行场景进入时候的方法 Onexit方法:负责实行场景退出时候的方法 脚本存放的位置: ...
- iOS之UI--主流框架的搭建-- 仿制QQ的UI框架
iOS之UI--主流框架的搭建-- 仿制QQ的UI框架 使用XCode搭建多个控制器界面,一般在实际开发中建议超过四个控制器界面使用纯代码. 下面的实例其实已经超过了四个,总结详细步骤的目的,主要是更 ...
最新文章
- Android——RatingBar(评价条)相关知识总结贴
- Druid数据库连接池使用
- OCP大会 | 腾讯云Open DCN Networking(附PDF)
- 深度学习之循环神经网络(11-a)LSTM情感分类问题代码
- 建立数组并写入数据_VBA数组与字典解决方案第37讲:在VBA中字典的应用
- exchange2003系列总结:-5邮件加密与签名的工作流程
- 零基础入门AI量化交易学习笔记
- 硬盘被计算机限制如果解锁,硬盘被锁怎么办
- 手机电脑普通浏览器或UC浏览器缓存或下载的Y2hlbmppbmdjb25n0 Y2hlbmppbmdjb25n1 m3u8视频.ts格式视频合并工具成一个mp4
- 第一个Python程序--Python
- 计算机符号mi,在线特殊符号大全
- 普通带条件查询接口报错 Handler dispatch failed; nested exception is java.lang.NoClassDefFoundError:
- java.library.path和LD_LIBRARY_PATH的介绍与区别
- Linux内存管理1---内存寻址
- android的视频直播,Android进行视频,直播播放
- 用计算机唱歌 丑八怪乐谱,得力计算器乐谱丑八怪 | 手游网游页游攻略大全
- 计算机网络 --- 计算机网络和因特网
- 非常精美的唐诗,无与伦比哦遥知兄弟登高处,遍插茱萸少一人。秦时明月汉时关,万里长征人未还。但使龙城飞将在,不教胡马度阴山。春眠不觉晓,处处闻啼鸟。夜来风雨声,花落知多少。君自故乡来,应知故乡事。来日绮
- 格兰仕滚筒洗衣机学习
- java输入和输出路径_Java输入输出
热门文章
- Redis从入门到精通
- LM75AD温度传感器的应用(1)
- bat中rar压缩命令
- 第二章第十六题(几何:六边形面积)(Geometry: area of a hexagon)
- 谁可以参与初创股权分配?
- php毕设代做,客户管理系统,java,jsp,php,好毕设为你指导如何完成一个客户管理系统...
- 信鸽推送集成采坑之代码混淆报错/XINGE: [Util] please add wup-1.0.0.E-SNAPSHOT.jar in your libs
- 电脑lol性能测试软件,lol电脑配置测试
- 直流电机驱动电路中L298与电机间二极管的作用
- 汪延谈王志东离职问题 (转)