基于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设计之初,就遵从从源端到目的的解耦性.下游可以有很多 ...
随机推荐
- 利用Travis CI+GitHub实现持续集成和自动部署
前言 如果你手动部署过项目,一定会深感持续集成的必要性,因为手动部署实在又繁琐又耗时,虽然部署流程基本固定,依然容易出错. 如果你很熟悉持续集成,一定会同意这样的观点:"使用它已经成为一种标 ...
- selenium实现百度图片爬取
因为是百度图片是瀑布流ajax异步上传的数据,所以这里用到抓包工具来抓取链接(fiddler) 好了直接上代码, from selenium import webdriver from seleniu ...
- Python Excel操作——xlrd、xlwd
读取 1.导入模块 import xlrd 2.打开Excel文件读取数据 data = xlrd.open_workbook('excel.xls') 3.获取一个工作表 1 table = dat ...
- Scala 学习笔记之集合(2)
class StudentTT extends StudentT{ def sayBye(name: String, age: Int)(address: String){ println(" ...
- 快学Scala 第三课 (定长数组,变长数组, 数组循环, 数组转换, 数组常用操作)
定长数组定义: val ar = new Array[Int](10) val arr = Array("aa", "bb") 定长数组赋值: arr(0) = ...
- Ubuntu18.04安装好MySQL5.7后,root账号登录密码问题
不知道从哪个版本开始,在Ubuntu上用apt安装MySQL后,不会提示让你设置密码了. 安装MySQL5.7 sudo apt install mysql-server -y 然后找到MySQL的配 ...
- Android中三种常用解析XML的方式(DOM、SAX、PULL)简介及区别
XML在各种开发中都广泛应用,Android也不例外.作为承载数据的一个重要角色,如何读写XML成为Android开发中一项重要的技能.今天就由我向大家介绍一下在Android平台下几种常见的XML解 ...
- 配置mysql可局域网内访问
一 进入mysql输入密码 :mysql -u root -p二 执行可局域网访问命令:GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY ...
- Angry Words 愤怒的话
_ Words said in anger are like scars left by nails in a fence. Even though you can pull all the nail ...
- badboy录制脚本
第一步:介绍badboy工具 1.1: 页面功能分析: 1. 界面视图,模拟浏览器,能够进行操作 2. 需要录制脚本的URL 3. 点击运行URL 4. Summary:运行的各指标,响应时间,成功事 ...