【Unity程序技巧】UI中心管理器

作者 : admin 本文共9232个字,预计阅读时间需要24分钟 发布时间: 2024-06-5 共4人阅读

【Unity程序技巧】UI中心管理器插图


👨‍💻个人主页:@元宇宙-秩沅

👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅!

👨‍💻 本文由 秩沅 原创

👨‍💻 收录于专栏

🅰️



文章目录

    • 🅰️
    • 前言
    • 🎶(==W==) 面板基类
      • 相关知识点
      • 特点
      • 脚本
    • 🎶(==W==) 管理器/font>
      • 准备
    • 🎶(==W==) 管理器优化——自定义事件监听
        • 特点
        • 脚本
        • 测试
    • 🅰️

前言


🎶(W 面板基类


相关知识点


【Unity程序技巧】UI中心管理器插图(1)

特点


  • 方便子类面板继承,并且可以获取面板中的控件脚本进行操作
  • 为一切面板类封装好了相同的方法
    【Unity程序技巧】UI中心管理器插图(2)

脚本


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
//UI 面板基类:
//目的:让子类继承
//功能:可快速找到面板中的控件然后对其进行操作 
public class BasePanel : MonoBehaviour
{
//UIBehaviour是所有UI控件的基类,通过里式转换原则 来存储所有的面板中的UI对象,运用list即可方便存储一个UI对象中的多个控件脚本
private Dictionary<string, List<UIBehaviour>> controlDic = new Dictionary<string, List<UIBehaviour>>();
protected virtual void Awake () {
FindChildrenControl<Button>();
FindChildrenControl<Image>();
FindChildrenControl<Text>();
FindChildrenControl<Toggle>();
FindChildrenControl<Slider>();
FindChildrenControl<ScrollRect>();
FindChildrenControl<InputField>();
}
4
// 面板基类自带的显示功能
4
public virtual void ShowMe()
{
}
// 面板基类自带的隐藏功能
public virtual void HideMe()
{
}
//鼠标响应函数:减去了存在多个按钮需要写多个响应事件的情况发生
protected virtual void OnClick(string btnName)
{
}
//值改变响应函数
protected virtual void OnValueChanged(string toggleName, bool value)
{
}
// 得到对应名字对象的对应控件脚本
protected T GetControl<T>(string controlName) where T : UIBehaviour
{
if(controlDic.ContainsKey(controlName))
{
for( int i = 0; i <controlDic[controlName].Count; ++i )
{
if (controlDic[controlName][i] is T)
return controlDic[controlName][i] as T;
}
}
return null;
}
// 找到自己子对象的对应控件脚本,边找边监听
private void FindChildrenControl<T>() where T:UIBehaviour //泛型约束为UI组件类型
{
//将控件的多个脚本
T[] controls = this.GetComponentsInChildren<T>();
for (int i = 0; i < controls.Length; ++i)
{
string objName = controls[i].gameObject.name;
if (controlDic.ContainsKey(objName))
controlDic[objName].Add(controls[i]);
else
controlDic.Add(objName, new List<UIBehaviour>() { controls[i] });
//如果是按钮控件
if(controls[i] is Button)
{
(controls[i] as Button).onClick.AddListener(()=>
{
OnClick(objName); //每一个按钮点击都会响应Onclick这个函数,通过传入名字参数则可以区分哪一个按钮
});
}
//如果是单选框或者多选框
else if(controls[i] is Toggle)
{
(controls[i] as Toggle).onValueChanged.AddListener((value) =>
{
OnValueChanged(objName, value);
});
}
//其他控件也是一样的以上只是两个例子(Buttom & Tolgle)
}
}
}

🎶(W 管理器/font>


准备

  • 首先给Canvas自定义设置父类层级
    【Unity程序技巧】UI中心管理器插图(3)

  • Canvas作为预制体时候的参数默认值修改

  • EventSystem也连带作为预制体
    【Unity程序技巧】UI中心管理器插图(4)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
//自定义Canvas枚举层级
public enum E_UI_Layer
{
Bottom,
Midle,
Top,
System,
}
/// UI管理器
/// 1.管理所有显示的面板
/// 2.提供给外部 显示和隐藏等等接口
public class UIManager : SingleManager <UIManager>
{
//里式转换原则:用面板相同的基类:BasePanel
public Dictionary<string, BasePanel> panelContorlDic = new Dictionary<string, BasePanel>();
private Transform bottom ;
private Transform midle;
private Transform top;
private Transform system;
//记录我们UI的Canvas父对象 方便以后外部可能会使用它
public RectTransform canvas;
//构造函数
//1.创建加载Canvas 
//2.找到Canvas预制体的层
//3.相同的也需要创建加载EventSystem 让其过场景的时候 不被移除
public UIManager() 
{
GameObject obj = ResourceManager .GetInstance().Load<GameObject>("(canvas预制体放到的文件夹路径)UI/Canvas");
canvas = obj.transform as RectTransform;
GameObject.DontDestroyOnLoad(obj);
bottom = canvas.Find("Bot");
midle = canvas.Find("Mid");
top = canvas.Find("Top");
system = canvas.Find("System");
obj = ResourceManager.GetInstance().Load<GameObject>("UI/EventSystem");
GameObject.DontDestroyOnLoad(obj);
}
// 通过层级枚举 得到对应层级的父对象
public Transform GetLayerFather(E_UI_Layer layer)
{
switch(layer)
{
case E_UI_Layer.Bottom:
return this.bottom;
case E_UI_Layer.Midle:
return this.midle;
case E_UI_Layer.Top:
return this.top;
case E_UI_Layer.System:
return this.system;
}
return null;
}
/// 
/// 显示面板
/// 
/// 面板脚本类型
/// 面板名
/// 显示在哪一层
/// 当面板预设体创建成功后 你想做的事
public void ShowPanel<T>(string panelName, E_UI_Layer layer = E_UI_Layer.Midle , UnityAction<T> callBack = null) where T: BasePanel //约束为面板
{
if (panelContorlDic.ContainsKey(panelName))
{
panelContorlDic[panelName].ShowMe();
//处理面板创建完成后的逻辑
if (callBack != null)
callBack(panelContorlDic[panelName] as T);
//避免面板重复加载 如果存在该面板 即直接显示 调用回调函数后  直接return 不再处理后面的异步加载逻辑
return;
}
ResourceManager.GetInstance().LoadAsync<GameObject>("存放面板的文件名/" + panelName, (obj) =>
{
//把他作为 Canvas的子对象
//并且 要设置它的相对位置
//找到父对象 你到底显示在哪一层
Transform father = bottom; //默认为底层
switch(layer)
{
case E_UI_Layer.Midle:
father = midle;
break;
case E_UI_Layer.Top:
father = top;
break;
case E_UI_Layer.System:
father = system;
break;
}
//设置父对象  设置相对位置和大小
obj.transform.SetParent(father);
//将面板对象的位置全部设置为默认值
obj.transform.localPosition = Vector3.zero;
obj.transform.localScale = Vector3.one;
(obj.transform as RectTransform).offsetMax = Vector2.zero;
(obj.transform as RectTransform).offsetMin = Vector2.zero;
//得到预设体身上的面板脚本
T panel = obj.GetComponent<T>();
//处理面板创建完成后的逻辑
if (callBack != null)
callBack(panel);
panel.ShowMe();
//把面板存起来
panelContorlDic .Add(panelName, panel);
});
}
/// 隐藏面板
public void HidePanel(string panelName)
{
if(panelContorlDic .ContainsKey(panelName))
{           
panelContorlDic[panelName].HideMe();
GameObject.Destroy(panelContorlDic[panelName].gameObject);
panelContorlDic.Remove(panelName);
}
}
// 得到某一个已经显示的面板 方便外部使用
public T GetPanel<T>(string name) where T:BasePanel
{
if (panelContorlDic .ContainsKey(name))
return panelContorlDic[name] as T;
return null;
}
/// 
/// 给控件添加自定义事件监听
/// 
/// 控件对象
/// 事件类型
/// 事件的响应函数
public static void AddCustomEventListener(UIBehaviour control, EventTriggerType type, UnityAction<BaseEventData> callBack)
{
EventTrigger trigger = control.GetComponent<EventTrigger>();
if (trigger == null)
trigger = control.gameObject.AddComponent<EventTrigger>();
EventTrigger.Entry entry = new EventTrigger.Entry();
entry.eventID = type;
entry.callback.AddListener(callBack);
trigger.triggers.Add(entry);
}
}

🎶(W 管理器优化——自定义事件监听


特点

为什么要添加?

因为每个控件的事件是单个的(要么是点击事件要么值改变事件),基于我们想多添加一些事件比如拖拽等,这就是我们优化添加自定义事件监听的目的

  • 自定义事件的添加
  • 原型如下,但我们的优化是完全用到代码添加自定义事件组件
    【Unity程序技巧】UI中心管理器插图(5)
脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
/// 
/// UI层级
/// 
public enum E_UI_Layer
{
Bottom,
Midle,
Top,
System,
}
/// 
/// UI管理器
/// 1.管理所有显示的面板
/// 2.提供给外部 显示和隐藏等等接口
/// 
public class UIManager : SingleManager <UIManager>
{
//里式转换原则:用面板相同的基类:BasePanel
public Dictionary<string, BasePanel> panelContorlDic = new Dictionary<string, BasePanel>();
private Transform bottom ;
private Transform midle;
private Transform top;
private Transform system;
//记录我们UI的Canvas父对象 方便以后外部可能会使用它
public RectTransform canvas;
//构造函数
//1.创建加载Canvas 
//2.找到Canvas预制体的层
//3.相同的也需要创建加载EventSystem 让其过场景的时候 不被移除
public UIManager() 
{
GameObject obj = ResourceManager .GetInstance().Load<GameObject>("(canvas预制体放到的文件夹路径)UI/Canvas");
canvas = obj.transform as RectTransform;
GameObject.DontDestroyOnLoad(obj);
bottom = canvas.Find("Bot");
midle = canvas.Find("Mid");
top = canvas.Find("Top");
system = canvas.Find("System");
obj = ResourceManager.GetInstance().Load<GameObject>("UI/EventSystem");
GameObject.DontDestroyOnLoad(obj);
}
/// 
/// 通过层级枚举 得到对应层级的父对象
/// 
/// 
/// 
public Transform GetLayerFather(E_UI_Layer layer)
{
switch(layer)
{
case E_UI_Layer.Bottom:
return this.bottom;
case E_UI_Layer.Midle:
return this.midle;
case E_UI_Layer.Top:
return this.top;
case E_UI_Layer.System:
return this.system;
}
return null;
}
/// 
/// 显示面板
/// 
/// 面板脚本类型
/// 面板名
/// 显示在哪一层
/// 当面板预设体创建成功后 你想做的事
public void ShowPanel<T>(string panelName, E_UI_Layer layer = E_UI_Layer.Midle , UnityAction<T> callBack = null) where T: BasePanel //约束为面板
{
if (panelContorlDic.ContainsKey(panelName))
{
panelContorlDic[panelName].ShowMe();
//处理面板创建完成后的逻辑
if (callBack != null)
callBack(panelContorlDic[panelName] as T);
//避免面板重复加载 如果存在该面板 即直接显示 调用回调函数后  直接return 不再处理后面的异步加载逻辑
return;
}
ResourceManager.GetInstance().LoadAsync<GameObject>("存放面板的文件名/" + panelName, (obj) =>
{
//把他作为 Canvas的子对象
//并且 要设置它的相对位置
//找到父对象 你到底显示在哪一层
Transform father = bottom; //默认为底层
switch(layer)
{
case E_UI_Layer.Midle:
father = midle;
break;
case E_UI_Layer.Top:
father = top;
break;
case E_UI_Layer.System:
father = system;
break;
}
//设置父对象  设置相对位置和大小
obj.transform.SetParent(father);
//将面板对象的位置全部设置为默认值
obj.transform.localPosition = Vector3.zero;
obj.transform.localScale = Vector3.one;
(obj.transform as RectTransform).offsetMax = Vector2.zero;
(obj.transform as RectTransform).offsetMin = Vector2.zero;
//得到预设体身上的面板脚本
T panel = obj.GetComponent<T>();
//处理面板创建完成后的逻辑
if (callBack != null)
callBack(panel);
panel.ShowMe();
//把面板存起来
panelContorlDic .Add(panelName, panel);
});
}
/// 
/// 隐藏面板
/// 
/// 
public void HidePanel(string panelName)
{
if(panelContorlDic .ContainsKey(panelName))
{           
panelContorlDic[panelName].HideMe();
GameObject.Destroy(panelContorlDic[panelName].gameObject);
panelContorlDic.Remove(panelName);
}
}
/// 
/// 得到某一个已经显示的面板 方便外部使用
/// 
public T GetPanel<T>(string name) where T:BasePanel
{
if (panelContorlDic .ContainsKey(name))
return panelContorlDic[name] as T;
return null;
}
/// 
/// 给控件添加自定义事件监听
/// 
/// 控件对象
/// 事件类型
/// 事件的响应函数
public static void AddCustomEventListener(UIBehaviour control, EventTriggerType type, UnityAction<BaseEventData> callBack)
{
//EvneTriggerType是枚举类型的变量它存储着各种事件
EventTrigger trigger = control.GetComponent<EventTrigger>();
if (trigger == null)
trigger = control.gameObject.AddComponent<EventTrigger>();
EventTrigger.Entry entry = new EventTrigger.Entry();
entry.eventID = type;                 //eventID事件类型的成员——>类型是什么
entry.callback.AddListener(callBack); //此时的entry.callback是一个它自带的事件类型——>响应的函数是什么
trigger.triggers.Add(entry);          //所有的事件监听都在triggers里面储存(虽然现在只是一个事件)
}
}
测试

  //体现基类当中监听的作用
protected override void OnClick(string btnName)
{
//假设这个面板当中有三个按钮: but1 ,but2 ,but3
switch(btnName )
{
case "but1":
Debug.Log("点击but1时执行的逻辑");
break;
case "but2":
Debug.Log("点击but2时执行的逻辑");
break;
case "but3":
Debug.Log("点击but3时执行的逻辑");
break;
}
}
 private void Start()
{
UIManager.GetInstance().ShowPanel<textPanel>("text", E_UI_Layer.Bottom, (callback) => { });
//体现管理器中的事件监听功能
UIManager.AddCustomEventListener(GetControl<Button>("but1"), EventTriggerType.PointerExit, (callback) =>
{
Debug.Log("离开");
});
}

🅰️


⭐【Unityc#专题篇】之c#进阶篇】

⭐【Unityc#专题篇】之c#核心篇】

⭐【Unityc#专题篇】之c#基础篇】

⭐【Unity-c#专题篇】之c#入门篇】

【Unityc#专题篇】—进阶章题单实践练习

⭐【Unityc#专题篇】—基础章题单实践练习

【Unityc#专题篇】—核心章题单实践练习


你们的点赞👍 收藏⭐ 留言📝 关注✅是我持续创作,输出优质内容的最大动力!


【Unity程序技巧】UI中心管理器插图(6)


本站无任何商业行为
个人在线分享 » 【Unity程序技巧】UI中心管理器
E-->