基于UGUI的框架
这个框架简单易懂,上手就可以直接拿来用,主要是单例管理类,界面和界面之间的互相交流通过单例去实现,个人感觉不是很好,但是我特别喜欢他的管理层级非常分明。
之后会发一个广播机制,结合上这套UI框架,但是本文主要是讲这个框架,所以后话就后话说吧,话不多说上代码
(一)UImanager:
以panel为编程单位,储存管理panel和下级控件,向外提供接口方法,接收界面和控件主动往管理类里注册,排查是否重复注册以及最后销毁等
注意:我在使用的时候发现还是有很多需要注意的问题的
1、UIManager必须游戏启动第一时间启动,整个游戏进程中不能销毁的,可以给个空物体,然后dontdestory,再动态addcompnent加入
2、整个框架主体分为三个脚本,执行顺序为 UIManager > UIBase > UIBehaviour,我在第一使用的时候发现,只要一加载界面就会报空,百思不其解,然后层层断点发现执行顺序的问题,UIBehaivour先执行了,导致找不到UIManager往里注册,有点坑
3、因为字典存的是界面name,控件name,控件对象,在RegistGameObject函数中会进行一次筛选,key不能相同,也就意味着界面名字不能重复,同界面的控件名字不能重复,我在做交易列表时被这个搞得头疼,一定要注意,加载完换个名字
using System.Collections.Generic;
using UnityEngine; public class UIManager : MonoBehaviour
{
Dictionary<string, Dictionary<string, GameObject>> allChild;
public static UIManager Instance; private GameObject mainCanvas;
public GameObject MainCanvas
{
get
{
if (mainCanvas == null)
{
mainCanvas = GameObject.FindGameObjectWithTag("MainCanvas");
}
return mainCanvas;
}
} public GameObject InstantiateUIPanelGameObject(string path, string endWithName = "", Transform parent = null)
{
if (parent == null)
{
parent = MainCanvas.transform;
}
GameObject tmpGameObj = Instantiate(Resources.Load<GameObject>(path));
tmpGameObj.name = tmpGameObj.name.Replace("(Clone)", endWithName);
tmpGameObj.transform.SetParent(parent,false);
return tmpGameObj;
} void Awake()
{
allChild = new Dictionary<string, Dictionary<string, GameObject>>();
Instance = this;
} /// <summary>
/// 可以拿到字典中已经注册过的panel下的控件
/// </summary>
/// <param name="panelName"></param>
/// <param name="widgeNmae"></param>
/// <returns></returns>
public GameObject GetGameObject(string panelName, string widgeNmae)
{
if (allChild.ContainsKey(panelName))
{
return allChild[panelName][widgeNmae];
}
return null;
} /// <summary>
/// 反注册,当你确定不再需要这个界面的时候,没必要浪费空间
/// </summary>
/// <param name="panelName"></param>
/// <param name="widgeName"></param>
public void UnRegistGameObject(string panelName, string widgeName)
{
if (allChild.ContainsKey(panelName))
{
if (allChild.ContainsKey(widgeName))
{
allChild[panelName].Remove(widgeName);
}
}
} /// <summary>
/// 销毁某个panel上所有控件
/// </summary>
/// <param name="panelName"></param>
public void DestroyAllWidgeFormPanel(string panelName)
{
if (allChild.ContainsKey(panelName))
{
if (allChild[panelName] != null)
{
allChild[panelName].Clear();
}
}
} /// <summary>
/// 供UIBehaviour调用,UIBehaviour每个控件都会动态挂载,并且在awake里面调用,注册自己
/// </summary>
/// <param name="panelName"></param>
/// <param name="widgeName"></param>
/// <param name="widge"></param>
public void RegistGameObject(string panelName, string widgeName, GameObject widge)
{
if (!allChild.ContainsKey(panelName))
{
allChild.Add(panelName, new Dictionary<string, GameObject>());
} if (!allChild[panelName].ContainsKey(widgeName))
{
allChild[panelName].Add(widgeName, widge);
}
else
{
Debug.LogError(" has been registed => " + widgeName);
}
} public void CleanDic()
{
allChild.Clear();
}
}
(二)UIBase:
这是一个供界面脚本继承的基类,前面也说次框架是以panel为编程单位的,这也就是说只要你想用这套框架,只需要在panel上挂载自己写的脚本去控制底下的所有控件即可,但是这个脚本必须继承UIBase
这里又存在一个硬性条件,那就是panel下,你所要写功能的控件,对象名的结尾必须_N,这是为了动态挂脚本UIBehaivour,我想这是为了让预设体或者AB尽量减少依赖吧
在UIBase里存着panel下所有的控件,不用再去find了,避免低效,同时在UIBase里对各种控件的回调进行了二次封装,直接调用传参就行,这点我很喜欢,简单粗暴
如果有需要,也可以自己拓展封装,底层回调在UIBehaivour封装,UIBase进行二次封装
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI; public class UIBase : MonoBehaviour
{
public Transform[] allChild; private void Awake()
{
// 将所有的子控件 获取到。
allChild = gameObject.GetComponentsInChildren<Transform>();
for (int i = ; i < allChild.Length; i++)
{
//以名字区别控件,动态挂载脚本,所以必须按规范命名
if (allChild[i].name.EndsWith("_N"))
{
allChild[i].gameObject.AddComponent<UIBehaviour>();
}
}
} public virtual void OnDestroy()
{
UIManagerLen.Instance.DestroyAllWidgeFormPanel(transform.name);
} /// <summary>
/// 从UIManager里面拿子控件
/// </summary>
/// <param name="widgaeName"></param>
/// <returns></returns>
public GameObject GetGameObject(string widgaeName)
{
return UIManagerLen.Instance.GetGameObject(transform.name, widgaeName);
} /// <summary>
/// 为了拿到底层封装
/// </summary>
/// <param name="widgaeName"></param>
/// <returns></returns>
public UIBehaviour GetBehavour(string widgaeName)
{
// 找对象
GameObject tmpBtn = GetGameObject(widgaeName);
if (tmpBtn)
{
// 拿到 UIBehavour
UIBehaviour behavour = tmpBtn.GetComponent<UIBehaviour>();
return behavour;
}
return null;
} /// <summary>
/// button
/// </summary>
/// <param name="widageName"></param>
/// <param name="action"></param>
public void AddButtonListen(string widageName, UnityAction action)
{
UIBehaviour behavour = GetBehavour(widageName);
if (behavour)
{
//绑定事件
behavour.AddButtonListener(action);
}
} /// <summary>
/// slider
/// </summary>
/// <param name="widageName"></param>
/// <param name="action"></param>
public void AddSliderListen(string widageName, UnityAction<float> action)
{
UIBehaviour behavour = GetBehavour(widageName);
if (behavour)
{
//绑定事件
behavour.AddSliderListen(action);
}
} /// <summary>
/// scroll view
/// </summary>
/// <param name="cellName"></param>
/// <param name="widageName"></param>
/// <param name="action"></param>
public void AddScrollListen(string widageName, UnityAction<Vector2> action)
{
UIBehaviour behavour = GetBehavour(widageName);
if (behavour)
{
//绑定事件
behavour.AddScrollListen(action);
}
} /// <summary>
/// dropdown
/// </summary>
/// <param name="widageName"></param>
/// <param name="action"></param>
public void AddDropDownListen(string widageName, UnityAction<int> action)
{
UIBehaviour behavour = GetBehavour(widageName);
if (behavour)
{
//绑定事件
behavour.AddDropDownListen(action);
}
} /// <summary>
/// toggle
/// </summary>
/// <param name="widageName"></param>
/// <param name="action"></param>
public void AddToggleListen(string widageName, UnityAction<bool> action)
{
UIBehaviour behavour = GetBehavour(widageName);
if (behavour)
{
//绑定事件
behavour.AddToggleListener(action);
}
} /// <summary>
/// inputfiled
/// </summary>
/// <param name="widageName"></param>
/// <param name="action"></param>
public void AddInputListen(string widageName, UnityAction<string> action)
{
UIBehaviour behavour = GetBehavour(widageName);
if (behavour)
{
//绑定事件
behavour.AddInputEndListen(action);
}
} /// <summary>
/// 文本赋值
/// </summary>
/// <param name="widageName"></param>
/// <param name="value"></param>
public void ChangeText(string widageName, string value)
{
UIBehaviour behavour = GetBehavour(widageName);
if (behavour)
{
//绑定事件
behavour.ChangeText(value);
}
} /// <summary>
/// 图片点击
/// </summary>
/// <param name="widageName"></param>
/// <param name="action"></param>
public void AddPointClick(string widageName, UnityAction<BaseEventData> action)
{
UIBehaviour behavour = GetBehavour(widageName);
if (behavour)
{
behavour.AddInterfaceLisenter(EventTriggerType.PointerClick, action);
}
} /// <summary>
/// 图片拖拽 开始,正在拖,结束
/// </summary>
/// <param name="widageName"></param>
/// <param name="action"></param>
public void AddBeginDrag(string widageName, UnityAction<BaseEventData> action)
{
UIBehaviour behavour = GetBehavour(widageName);
if (behavour)
{
behavour.AddInterfaceLisenter(EventTriggerType.BeginDrag, action);
}
}
public void AddOnDrag(string widageName, UnityAction<BaseEventData> action)
{
UIBehaviour behavour = GetBehavour(widageName);
if (behavour)
{
behavour.AddInterfaceLisenter(EventTriggerType.Drag, action);
}
}
public void AddEndDrag(string widageName, UnityAction<BaseEventData> action)
{
UIBehaviour behavour = GetBehavour(widageName);
if (behavour)
{
behavour.AddInterfaceLisenter(EventTriggerType.EndDrag, action);
}
} /// <summary>
/// 更换图片
/// </summary>
/// <param name="widageName"></param>
/// <param name="value"></param>
public void SetImage(string widageName, Sprite value)
{
UIBehaviour subManager = GetBehavour(widageName);
if (subManager)
{
subManager.GetComponent<Image>().sprite = value;
}
} /// <summary>
/// 获取图片
/// </summary>
/// <param name="widageName"></param>
/// <returns></returns>
public Image GetImage(string widageName)
{
UIBehaviour behavour = GetBehavour(widageName);
if (behavour)
{
return behavour.GetImage();
}
return null;
} /// <summary>
/// 拿到text组件的值
/// </summary>
/// <param name="widageName"></param>
/// <returns></returns>
public string GetText(string widageName)
{
UIBehaviour behavour = GetBehavour(widageName);
if (behavour)
{
return behavour.GetText();
}
return null;
}
}
(三)UIBehaivour:
这个脚本就是动态挂载各个控件上的脚本,作用只有两个
1、向UIManager注册,接受管理
2、底层回调封装,供UIBase调用从而进行二次封装后直接使用 如果需要拓展也是从这里开始
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems; public class UIBehaviour : MonoBehaviour
{
UIBase tmpBase;
private void Awake()
{
tmpBase = gameObject.GetComponentInParent<UIBase>();//找到父类,也就是panel UIManagerLen.Instance.RegistGameObject(tmpBase.name, transform.name, gameObject);//向管理类注册自己
} private void OnDestroy()
{
UIManagerLen.Instance.UnRegistGameObject(tmpBase.name, gameObject.name);
} #region UGUI各种控件的回调封装
public void AddButtonListener(UnityAction action)//按钮回调封装
{
Button tmpBtn = gameObject.GetComponent<Button>();
if (tmpBtn) tmpBtn.onClick.AddListener(action);
}
public void AddSliderListen(UnityAction<float> action)//滚动条回调封装
{
Slider tmpBtn = gameObject.GetComponent<Slider>();
if (tmpBtn) tmpBtn.onValueChanged.AddListener(action);
}
public void AddDropDownListen(UnityAction<int> action)//下拉框回调封装
{
Dropdown tmpBtn = gameObject.GetComponent<Dropdown>();
if (tmpBtn) tmpBtn.onValueChanged.AddListener(action);
}
public void AddScrollListen(UnityAction<Vector2> action)//滚动框回调封装
{
ScrollRect tmpBtn = gameObject.GetComponent<ScrollRect>();
if (tmpBtn) tmpBtn.onValueChanged.AddListener(action);
}
public void AddToggleListener(UnityAction<bool> action)
{
Toggle tmpToggle = gameObject.GetComponent<Toggle>();
if (tmpToggle) tmpToggle.onValueChanged.AddListener(action);
}
public void AddInputEndListen(UnityAction<string> action)//输入框回调封装
{
InputField tmpBtn = GetComponent<InputField>();
if (tmpBtn) tmpBtn.onEndEdit.AddListener(action);
}
public void ChangeText(string value)//改变文本的接口
{
Text tmpBtn = gameObject.GetComponent<Text>();
if (tmpBtn) tmpBtn.text = value;
}
public Image GetImage()//如果控件是图片,提供获取图片的接口
{
Image tmpBtn = gameObject.GetComponent<Image>();
return tmpBtn;
}
public string GetText()//如果控件是文本,提供获取文本的接口
{
Text tmpBtn = gameObject.GetComponent<Text>();
return tmpBtn.text;
}
#endregion /// <summary>
/// 用代码动态添加接口事件
/// </summary>
/// <param name="action"></param>
public void AddInterfaceLisenter(EventTriggerType triger, UnityAction<BaseEventData> action)
{ EventTrigger trigger = gameObject.GetComponent<EventTrigger>(); if (trigger == null)
trigger = gameObject.AddComponent<EventTrigger>(); EventTrigger.Entry entry = new EventTrigger.Entry();
//绑定哪个接口
entry.eventID = triger; entry.callback = new EventTrigger.TriggerEvent(); entry.callback.AddListener(action); trigger.triggers.Add(entry);
}
}
(四)使用:
继承,调用就行了,简单示例一下
总结:
这个框架有优点,也有缺点
优点是层级管理分明,分工明确,封装之后调用简单方便
缺点界面和界面的交流,以及模块和模块之间的交流,耦合性还是不能很好的解决
有时间会写一套广播机制,配合着使用,已达到尽可能解耦的效果
基于UGUI的框架的更多相关文章
- Siki_Unity_3-6_UI框架 (基于UGUI)
Unity 3-6 UI框架 (基于UGUI) 任务1&2&3&4:介绍 && 创建工程 UI框架: 管理场景中所有UI面板 控制面板之间的跳转 如果没有UI框 ...
- Unity——基于UGUI的UI框架
基于UGUI的UI框架 一.Demo展示 二.关键类 MonoSingle 继承MonoBehaviour的单例基类:做了一些特殊处理: 保证场景中必须有GameInit名称的物体,所有单例管理器脚本 ...
- 基于Java Netty框架构建高性能的部标808协议的GPS服务器
使用Java语言开发一个高质量和高性能的jt808 协议的GPS通信服务器,并不是一件简单容易的事情,开发出来一段程序和能够承受数十万台车载接入是两码事,除去开发部标808协议的固有复杂性和几个月长周 ...
- 基于Typecho CMS框架开发大中型应用
基于Typecho CMS框架开发大中型应用 大中型应用暂且定义为:大于等于3个数据表的应用!汗吧! Typecho原本是一款博客系统,其框架体系有别于市面上一般意义MVC框架,主体代码以自创的Wid ...
- 基于AForge.Net框架的扑克牌识别
原文:基于AForge.Net框架的扑克牌识别 © 版权所有 野比 2012 原文地址:点击查看 作者:Nazmi Altun Nazmi Altun著,野比 译 下载源代码 - 148.61 KB ...
- 基于BrokerPattern服务器框架
基于BrokerPattern服务器框架 RedRabbit 经典网游服务器架构 该图省略了专门用途的dbserver.guildserver等用于专门功能的server,该架构的优点有: l Log ...
- 手工搭建基于ABP的框架(2) - 访问数据库
为了防止不提供原网址的转载,特在这里加上原文链接: http://www.cnblogs.com/skabyy/p/7517397.html 本篇我们实现数据库的访问.我们将实现两种数据库访问方法来访 ...
- 手工搭建基于ABP的框架 - 工作单元以及事务管理
一个业务功能往往不只由一次数据库请求(或者服务调用)实现.为了功能的完整性,我们希望如果该功能执行一半时出错,则撤销前面已执行的改动.在数据库层面上,事务管理实现了这种完整性需求.在ABP中,一个完整 ...
- 基于Kafka Connect框架DataPipeline可以更好地解决哪些企业数据集成难题?
DataPipeline已经完成了很多优化和提升工作,可以很好地解决当前企业数据集成面临的很多核心难题. 1. 任务的独立性与全局性. 从Kafka设计之初,就遵从从源端到目的的解耦性.下游可以有很多 ...
随机推荐
- .Net Core 商城微服务项目系列(十):使用SkyWalking构建调用链监控(2019-02-13 13:25)
SkyWalking的安装和简单使用已经在前面一篇介绍过了,本篇我们将在商城中添加SkyWalking构建调用链监控. 顺带一下怎么把ES设置为Windows服务,cd到ES的bin文件夹,运行ela ...
- 整理基础的CentOS常用命令
如何知道apache装在哪里? which httpd 1.查看系统使用端口并释放端口 [root@my_nn_01 WEB-INF]# lsof -w -n -i tcp:80 COMMAND ...
- spring配置文件默认名称及位置,ContextLoaderListener监听器作用
spring在web.xml中的配置 由于spring需要启动容器才能为其他框架提供服务,而web应用程序的入口是由web服务器控制的,因此无法在main()方法中通过创建ClassPathXmlAp ...
- java的动手动脑10月20日
(1)动手动脑 该函数没有赋初值再就是如果类提供一个自定义的构造方法,将导致系统不在提供默认的构造方法. (2) public class test { /*** @param args*/publi ...
- 基于AHB总线的master读写设计(Verilog)
一.AHB总线学习 1. AHB总线结构 如图所示,AHB总线系统利用中央多路选择机制实现主机与从机的互联问题.从图中可以看出,AHB总线结构主要可分为三部分:主机.从机.控制部分.控制部分由仲裁器. ...
- PHP array_reduce
1.函数的作用:用函数迭代数组的所有元素 2.函数的参数: @params array $array 用于迭代的数组 @params callable $callback 迭代的函数 @ ...
- PHP array_fill_keys
1.函数的作用:将一个数组的元素分别作为键值和一个指定的值组成新的数组: 2.函数的参数: @params array $array @params mixed $values 3.例子: < ...
- JavaScript 编译器-Babel
Babel是一个广泛使用的转码器,可以将ES6代码转为ES5代码,从而在现有环境执行.这意味着,你可以现在就用ES6.ES7编写程序,而不用担心现有环境是否支持. 一.全局安装babel工具 在保证n ...
- [Luogu3868] [TJOI2009]猜数字
题目描述 现有两组数字,每组k个,第一组中的数字分别为:a1,a2,...,ak表示,第二组中的数字分别用b1,b2,...,bk表示.其中第二组中的数字是两两互素的.求最小的非负整数n,满足对于任意 ...
- netty中Pipeline的ChannelHandler执行顺序案例详解
一.netty的Pipeline模型 netty的Pipeline模型用的是责任链设计模式,当boss线程监控到绑定端口上有accept事件,此时会为该socket连接实例化Pipeline,并将In ...