基于UGUI的UI框架


一.Demo展示


二.关键类

MonoSingle

继承MonoBehaviour的单例基类;做了一些特殊处理;

保证场景中必须有GameInit名称的物体,所有单例管理器脚本都挂在该物体上;

继承单例基类后,需要私有化构造;

public class MonoSingle<T> : MonoBehaviour where T :MonoSingle<T>
{
protected static T instance; public static T I
{
get
{
if (instance == null)
{
GameObject go = GameObject.Find("GameInit");
if (go == null)
{
go = new GameObject("GameInit");
DontDestroyOnLoad(go);
} instance = go.GetComponent<T>(); if (instance == null)
instance = go.AddComponent<T>();
}
return instance;
}
}
}

UIType

所有UI的面板都需要在这个类中添加常量字段,方便比对;

public class UIType
{
public const string UIMain = "panmain";
public const string UIInventory = "paninventory";
public const string UIShop = "panshop";
public const string UIQuest = "panquest";
public const string UIEquipment = "panequipment";
public const string UISkill = "panskill";
}

创建UI层级枚举,根据层级设置UI面板的父节点

public enum UILayer
{
Back, //背景层
Default, //默认层
Pop, //弹窗
Top //顶层,适用悬浮等
}

UIBase

所有UI面板的基类;创建新的UI面板必须继承UIBase同时重写虚方法

public abstract class UIBase : MonoBehaviour
{
//层级字段,根据层级设置父节点
public UILayer uiLayer;
//UI类型字段
public string uiType; //面板进入时调用
public virtual void OnEnter()
{
//设置父节点
transform.SetParent(UIManager.I.dicLayer[uiLayer]);
} //面板停止时调用(鼠标与面板的交互停止)
public virtual void OnPause()
{
} //面板恢复使用时调用(鼠标与面板的交互恢复)
public virtual void OnResume()
{
} //面板退出时调用
public virtual void OnExit()
{
}
}

UIManager

//partial拆分类,有点像.h和.cpp的区别,但是只是把一个类分成两个写
public partial class UIManager : MonoSingle<UIManager>
{
//所有UI面板perfab的路径key:UIType——value:Resources下的路径
public Dictionary<string, string> dicPath;
//根据上面路径,加载的好的具体的UI面板类
public Dictionary<string, UIBase> dicPanel;
//栈存储所有打开的UI面板,打开UI,push栈,关闭UI,pop栈
private Stack<UIBase> panelStack;
//canvas.transform 方便设置父节点
public Transform canvasTf;
//存储UI层级节点,方便设置父节点
public Dictionary<UILayer, Transform> dicLayer;
//存储UI层级对应的名称,用来加载ui层级节点时命名
public Dictionary<UILayer, string> dicLayerName; private UIManager()
{
//初始化perfab路径和ui层级节点
InitPath();
InitUILayer();
} public void Awake()
{
canvasTf = GameObject.Find("Canvas").transform;
//加载层级节点
LoadLayer();
} private void LoadLayer()
{
dicLayer = new Dictionary<UILayer, Transform>();
for (int i = 0; i < dicLayerName.Count; ++i)
{
GameObject layer = new GameObject(dicLayerName[(UILayer)i]);
layer.transform.SetParent(canvasTf);
dicLayer.Add((UILayer) i, layer.transform);
}
} //获取dicPanel中存储的基层UIBase的类,如果为空,先加载添加进去
private UIBase GetPanel(string panelType)
{
if (dicPanel == null)
dicPanel = new Dictionary<string, UIBase>(); panelType = panelType.ToLower();
if (dicPanel.ContainsKey(panelType))
return dicPanel[panelType];
else
{
string path = string.Empty;
if (dicPath.ContainsKey(panelType))
path = dicPath[panelType];
else
return null; GameObject go = Resources.Load<GameObject>(path);
GameObject goPanel = GameObject.Instantiate(go, canvasTf, false);
UIBase panel = goPanel.GetComponent<UIBase>();
dicPanel.Add(panelType, panel);
return panel;
}
} //打开UI界面
public void PushPanel(string panelType)
{
if (panelStack == null)
{
panelStack = new Stack<UIBase>();
} //停止上一个界面
if (panelStack.Count > 0)
{
UIBase top = panelStack.Peek();
top.OnPause();
} UIBase panel = GetPanel(panelType);
panelStack.Push(panel);
panel.OnEnter();
} //关闭最上层界面
public void PopPanel()
{
if (panelStack == null)
{
panelStack = new Stack<UIBase>();
}
if (panelStack.Count <= 0)
{
return;
} //退出栈顶面板
UIBase top = panelStack.Pop();
top.OnExit(); //恢复上一个面板
if (panelStack.Count > 0)
{
UIBase panel = panelStack.Peek();
panel.OnResume();
}
} //获取最上层面板
public UIBase GetTopPanel()
{
if (panelStack.Count > 0)
return panelStack.Peek();
else
return null;
}
}

使用partial最主要原因是想把加载和逻辑分开,加载部分类可以使用ScriptableObject自动生成或使用json外部读取;

我这里demo就手动添加了;

public partial class UIManager : MonoSingle<UIManager>
{
private void InitPath()
{
dicPath = new Dictionary<string, string>();
//自动生成代码,或使用json加载
dicPath["panmain"] = "UIPanel/PanMain";
dicPath["paninventory"] = "UIPanel/paninventory";
dicPath["panskill"] = "UIPanel/panskill";
dicPath["panquest"] = "UIPanel/panquest";
dicPath["panequipment"] = "UIPanel/panequipment";
dicPath["panshop"] = "UIPanel/panshop";
} private void InitUILayer()
{
dicLayerName = new Dictionary<UILayer, string>();
dicLayerName.Add(UILayer.Back,"Front");
dicLayerName.Add(UILayer.Default,"Default");
dicLayerName.Add(UILayer.Pop,"Pop");
dicLayerName.Add(UILayer.Top,"Top");
}
}

三.测试用类

Pan开头类

PanMain主界面,打开后一直显示,不会隐藏;

public class PanMain : UIBase
{
PanMain()
{
//初始化UIBase中层级和类型字段
uiLayer = UILayer.Default;
uiType = UIType.UIMain;
} //打开界面按钮,公有字段,inspector界面赋值
public Button btnInventory;
public Button btnShop;
public Button btnSkill;
public Button btnQuest;
public Button btnEquipment; public override void OnEnter()
{
base.OnEnter();
Debug.Log("打开Mian"); //封装的按钮添加事件方法,点击打开或关闭
AddBtnListener(btnEquipment,UIType.UIEquipment);
AddBtnListener(btnShop,UIType.UIShop);
AddBtnListener(btnSkill,UIType.UISkill);
AddBtnListener(btnQuest,UIType.UIQuest);
AddBtnListener(btnInventory,UIType.UIInventory);
} private void AddBtnListener(Button go,string type)
{
go.onClick.AddListener(() =>
{
if (UIManager.I.GetTopPanel().uiType == type)
UIManager.I.PopPanel();
else
UIManager.I.PushPanel(type);
});
} public override void OnPause()
{
//取消下面注释,打开新界面时,主界面按钮会失效
//ChangeBtnState(false);
} public override void OnResume()
{
//ChangeBtnState(true);
} public override void OnExit()
{
} //按钮失效代码
public void ChangeBtnState(bool value)
{
btnInventory.enabled = value;
btnShop.enabled = value;
btnSkill.enabled = value;
btnQuest.enabled = value;
btnEquipment.enabled = value;
}
}

PanInventory背包,其他shop,quest,equip,skill等逻辑相似,就只分析一个了;

public class PanInventory : UIBase
{
PanInventory()
{
uiLayer = UILayer.Default;
uiType = UIType.UIInventory;
} //关闭界面按钮
public Button btnClose; public void Start()
{
btnClose.onClick.AddListener(() => { UIManager.I.PopPanel(); });
} public override void OnEnter()
{
base.OnEnter();
this.gameObject.SetActive(true);
} //非顶层时按钮是否失效,可自行设置;
public override void OnPause()
{
//btnClose.enabled = false;
} public override void OnResume()
{
//btnClose.enabled = true;
} public override void OnExit()
{
this.gameObject.SetActive(false);
}
}

GameInit

public class GameInit : MonoSingle<GameInit>
{
private void Awake()
{
DontDestroyOnLoad(this.gameObject);
//打开主界面
UIManager.I.PushPanel(UIType.UIMain);
}
}

运行前:

运行后:

由于目前硬件性能和内存完全够用的情况下,所有UI面板加载一次后不会被销毁,只会被隐藏;

改Demo已被我上传至Gitee,可自行下载学习;

https://gitee.com/small-perilla/uiframe-demo

Unity——基于UGUI的UI框架的更多相关文章

  1. 基于Vue的Ui框架

    基于Vue的Ui框架 饿了么公司基于vue开的的vue的Ui组件库 Element Ui 基于vue pc端的UI框架 http://element.eleme.io/ MintUi 基于vue 移动 ...

  2. element-ui iview-admin 都是基于vue的ui框架

    element-ui iview-admin 都是基于vue的ui框架

  3. 基于vue的UI框架集锦

    前端框架百花齐放.争奇斗艳,令人眼花缭乱.大神们一言不合就整一个框架出来,另小白们无所适从.下面罗列了一些比较优秀的UI框架,Star多的大都是老牌劲旅,Star少的许多是后起之秀. (1)Eleme ...

  4. 基于Ant Design UI框架的React项目

    概述 这款基于React开发的UI框架,界面非常简洁美观,在这篇文章中我主要为大家介绍一下如何用Ant开始搭建React项目 详细 代码下载:http://www.demodashi.com/demo ...

  5. 移动端Rem适配(基于vue-cli3 ,ui框架用的是vant-ui)

    介绍postcss-pxtorem 是一款 postcss 插件,用于将单位转化为 remlib-flexible 用于设置 rem 基准值 1.安装lib-flexible(用于设置 rem 基准值 ...

  6. 前端基于jquery的UI框架

    正在做的一个项目选择jquery作为前端js核心库.然后就想选一个基于jquery的ui库,然后悲催的事情发生了. 至于为什么使用jquery,一是因为不想为授权费用,而又不想引起可能法律纠纷:另一方 ...

  7. 基于vue 的 UI框架 -- Mint UI

    网址: http://mint-ui.github.io/docs/#!/zh-cn 官网: http://mint-ui.github.io/#!/zh-cn vue2.0实例: http://bl ...

  8. 基于Vue的UI框架element el-table表格的自定义排序

    html部分: <el-table-column prop="phoneCache" label="手机缓存包编号" align="center ...

  9. 推荐一个基于Vue2.0的的一款移动端开发的UI框架,特别好用。。。

    一丶YDUI 一只注重审美,且性能高效的移动端&微信UI. 下面为地址自己研究去吧! 我的项目正在用,以前用的Mint-ui但是现在感觉还是这个好一点,官方给出的解释很清楚,很实用. 官方地址 ...

随机推荐

  1. tar.gz 文件解压

    tar.gz 文件解压 解压缩 file.tar.gz 的过程中出现如下所示问题: tar: 它似乎不像是一个 tar 归档文件 tar: 跳转到下一个头 tar: 由于前次错误,将以上次的错误状态退 ...

  2. mzy对于枚举的理解

    关于enum,其实就是简化了的class,功能就是提供一个个独立的.特定含义的常量! 在JDK5.0之前我们想模拟enum的功能,只能使用自定义类的形式: 1.首先私有化构造方法,让外部不能new对象 ...

  3. Linux从头学09:x86 处理器如何进行-层层的内存保护?

    作 者:道哥,10+年的嵌入式开发老兵. 公众号:[IOT物联网小镇],专注于:C/C++.Linux操作系统.应用程序设计.物联网.单片机和嵌入式开发等领域. 公众号回复[书籍],获取 Linux. ...

  4. Heartbeat MySQL双主复制

    目录 一 基础环境 二 实际部署 2.1 安装MySQL 2.2 初始化MySQL 2.3 master01 my.cf配置 2.4 创建账号 2.5 master02 my.cf配置配置 2.6 创 ...

  5. TypeScript 中枚举类型的理解?应用场景?

    一.是什么 枚举是一个被命名的整型常数的集合,用于声明一组命名的常数,当一个变量有几种可能的取值时,可以将它定义为枚举类型 通俗来说,枚举就是一个对象的所有可能取值的集合 在日常生活中也很常见,例如表 ...

  6. kubernetes 安装 ingress controller

    文章链接 ingress-nginx ingress 官方网站 ingress 仓库地址 ingress-nginx v1.0 最新版本 v1.0 适用于 Kubernetes 版本 v1.19+ ( ...

  7. Windows下安装Apollo时的几个常见问题

    今天在本地安装Apollo时遇到几个问题,觉得还是记录下来,希望能给有需要的朋友提供帮助. 安装的过程参考这篇教程,https://www.jianshu.com/p/6cf4b15ba82f.流程基 ...

  8. python轻量级orm框架 peewee常用功能速查

    peewee常用功能速查 peewee 简介 Peewee是一种简单而小的ORM.它有很少的(但富有表现力的)概念,使它易于学习和直观的使用. 常见orm数据库框架 Django ORM peewee ...

  9. Intel® QAT 加速卡之IPSec示例

    Intel QAT 加速卡之IPSec示例 文章目录 Intel QAT 加速卡之IPSec示例 1. QAT处理IPSec入站报文 2. QAT处理IPSec出站报文 3. 组织架构 4. 示例源码 ...

  10. vim的配置文件

    网上一个比较常见的配置文件设置如下,这个配置还是很棒的,尤其创建脚本或者c文件时 " All system-wide defaults are set in $VIMRUNTIME/debi ...