这个框架简单易懂,上手就可以直接拿来用,主要是单例管理类,界面和界面之间的互相交流通过单例去实现,个人感觉不是很好,但是我特别喜欢他的管理层级非常分明。

之后会发一个广播机制,结合上这套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的框架的更多相关文章

  1. Siki_Unity_3-6_UI框架 (基于UGUI)

    Unity 3-6 UI框架 (基于UGUI) 任务1&2&3&4:介绍 && 创建工程 UI框架: 管理场景中所有UI面板 控制面板之间的跳转 如果没有UI框 ...

  2. Unity——基于UGUI的UI框架

    基于UGUI的UI框架 一.Demo展示 二.关键类 MonoSingle 继承MonoBehaviour的单例基类:做了一些特殊处理: 保证场景中必须有GameInit名称的物体,所有单例管理器脚本 ...

  3. 基于Java Netty框架构建高性能的部标808协议的GPS服务器

    使用Java语言开发一个高质量和高性能的jt808 协议的GPS通信服务器,并不是一件简单容易的事情,开发出来一段程序和能够承受数十万台车载接入是两码事,除去开发部标808协议的固有复杂性和几个月长周 ...

  4. 基于Typecho CMS框架开发大中型应用

    基于Typecho CMS框架开发大中型应用 大中型应用暂且定义为:大于等于3个数据表的应用!汗吧! Typecho原本是一款博客系统,其框架体系有别于市面上一般意义MVC框架,主体代码以自创的Wid ...

  5. 基于AForge.Net框架的扑克牌识别

    原文:基于AForge.Net框架的扑克牌识别 © 版权所有 野比 2012 原文地址:点击查看 作者:Nazmi Altun Nazmi Altun著,野比 译  下载源代码 - 148.61 KB ...

  6. 基于BrokerPattern服务器框架

    基于BrokerPattern服务器框架 RedRabbit 经典网游服务器架构 该图省略了专门用途的dbserver.guildserver等用于专门功能的server,该架构的优点有: l Log ...

  7. 手工搭建基于ABP的框架(2) - 访问数据库

    为了防止不提供原网址的转载,特在这里加上原文链接: http://www.cnblogs.com/skabyy/p/7517397.html 本篇我们实现数据库的访问.我们将实现两种数据库访问方法来访 ...

  8. 手工搭建基于ABP的框架 - 工作单元以及事务管理

    一个业务功能往往不只由一次数据库请求(或者服务调用)实现.为了功能的完整性,我们希望如果该功能执行一半时出错,则撤销前面已执行的改动.在数据库层面上,事务管理实现了这种完整性需求.在ABP中,一个完整 ...

  9. 基于Kafka Connect框架DataPipeline可以更好地解决哪些企业数据集成难题?

    DataPipeline已经完成了很多优化和提升工作,可以很好地解决当前企业数据集成面临的很多核心难题. 1. 任务的独立性与全局性. 从Kafka设计之初,就遵从从源端到目的的解耦性.下游可以有很多 ...

随机推荐

  1. 正睿国庆DAY2动态规划专题

    正睿国庆DAY2动态规划专题 排列-例题 1~n 的排列个数,每个数要么比旁边两个大,要么比旁边两个小 \(f[i][j]\) 填了前i个数,未填的数有\(j\)个比第\(i\)个小,是波峰 \(g[ ...

  2. 我的mongoDb之旅(二)

    题序:上一回,咱们简单的操作了一些增减改查的操作,这一次,再来进行一场奇妙之旅 一.案例讲解 (1).字段有值与没值时的单条数据 第一条数据title这个字段(mysql用久了,习惯这么叫了)是没有数 ...

  3. centos7.x 部署主、从DNS服务器

    1.准备 例:两台192.168.219.146(主), 192.168.219.147(从), 域名www.panyangduola.com 主.从DNS服务器均需要安装bind.bind-chro ...

  4. ELK 学习笔记之 elasticsearch Mget操作

    Mget操作: 查询多个文档: curl -XGET 'http://192.168.1.151:9200/_mget' -d '{"docs": [{"_index&q ...

  5. 文件/大文件上传功能实现(JS+PHP)全过程

    文件/大文件上传功能实现(JS+PHP) 参考博文:掘金-橙红年代 前端大文件上传 路漫漫 其修远 PHP + JS 实现大文件分割上传 本文是学习文件上传后的学习总结文章,从无到有实现文件上传功能, ...

  6. deferred对象和promise对象(二)---deferred对象

    早上醒来,继续讨论deferred对象和primise对象. deferred对象的的方法: 1.$.Deferred()-----生成一个deferred对象 2.deferred.done()-- ...

  7. Kubernetes网络分析之Flannel

    Flannel是cereos开源的CNI网络插件,下图flannel官网提供的一个数据包经过封包.传输以及拆包的示意图,从这个图片中可以看出两台机器的docker0分别处于不同的段:10.1.20.1 ...

  8. 走进JavaWeb技术世界1:JavaWeb的由来和基础知识

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  9. Kubernetes之Flannel介绍

    Flannel是CoreOS团队针对Kubernetes设计的一个网络规划服务,简单来说,它的功能是让集群中的不同节点主机创建的Docker容器都具有全集群唯一的虚拟IP地址. 在Kubernetes ...

  10. unittest生成测试报告

    1.先导入HTMLTestRunner模块 2.实例一脚本如下 #coding=utf-8 import unittest import HTMLTestRunner #封装批量执行用例 def al ...