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

之后会发一个广播机制,结合上这套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. 【钢琴伴奏基本形态和伴奏织体】技能 get

    开头重复一句话:做编曲就是设计和声+伴奏织体. ---- --------- --------------- 分解和弦: 半分解和弦: 做法:在旋律的下方演奏一些和弦的音.就能让音乐更加的饱满,拒绝空 ...

  2. 第一篇:php开发环境

    Window: 1.XAMPPhttps://www.apachefriends.org/index.html 2.WampServerhttp://www.wampserver.com/ Linux ...

  3. dedecms新增联动类别后的使用方法

    近期用织梦的联动类别,后台明明可以直接新增联动类别,但是你直接调用是绝对调用不出来的............. 折腾了好几天终于全部解决,回忆下过程以便日后再遇到的时候参考. 第一步:先按照常规的在后 ...

  4. CSS技巧 (2) · 多列等高布局

    前言  最近,面试的时候都碰到一些关于利用CSS实现多列等高布局或者一侧宽度固定,另一侧宽度自适应的问题,下面稍微总结一下: 先看一道题目 巧妙的多列等高布局 规定下面的布局,实现多列等高布局,要求两 ...

  5. 微人事 star 数超 10k,如何打造一个 star 数超 10k 的开源项目

    看了下,微人事(https://github.com/lenve/vhr)项目 star 数超 10k 啦,松哥第一个 star 数过万的开源项目就这样诞生了. 两年前差不多就是现在这个时候,松哥所在 ...

  6. 移动端的<meta>标签

    <head> <meta charset="UTF-8" /> <!-- 页面关键词 --> <meta name="keywo ...

  7. 微信开发中使用微信JSSDK和使用URL.createObjectURL上传预览图片的不同处理对比

    在做微信公众号或者企业微信开发业务应用的时候,我们常常会涉及到图片预览.上传等的处理,往往业务需求不止一张图片,因此相对来说,需要考虑的全面一些,用户还需要对图片进行预览和相应的处理,在开始的时候我使 ...

  8. [BZOJ2724] 蒲公英

    题目背景 亲爱的哥哥: 你在那个城市里面过得好吗? 我在家里面最近很开心呢.昨天晚上奶奶给我讲了那个叫「绝望」的大坏蛋的故事的说!它把人们的房子和田地搞坏,还有好多小朋友也被它杀掉了.我觉得把那么可怕 ...

  9. Spring容器启动源码解析

    1. 前言 最近搭建的工程都是基于SpringBoot,简化配置的感觉真爽.但有个以前的项目还是用SpringMvc写的,看到满满的配置xml文件,却有一种想去深入了解的冲动.折腾了好几天,决心去写这 ...

  10. docker-compose 的使用

    1.安装docker-compose,参考官方教程:https://docs.docker.com/compose/install/ [chenjl@ipha-dev71- ~]$ sudo curl ...