UI基类
统一管理UI以及相关(UGUI),提高代码复用率,降低文件耦合性。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class PanelBase : MonoBehaviour
{
private Dictionary<string, List<UIBehaviour>> dict_allUI = new Dictionary<string, List<UIBehaviour>>();
protected void Awake()
{
FindAllControl();
}
/// <summary>
/// 查找所有子节点控件
/// </summary>
protected virtual void FindAllControl()
{
FindChildControl<Button>();
FindChildControl<Image>();
FindChildControl<Text>();
FindChildControl<Toggle>();
FindChildControl<ScrollRect>();
FindChildControl<Slider>();
}
/// <summary>
/// 得到对应名字的对应控件脚本
/// </summary>
/// <param name="sControlName">控件名字</param>
/// <typeparam name="T">泛型, 指UI控件</typeparam>
/// <returns>返回对应的ui控件, 不存在则返回null值</returns>
protected T GetControl<T>(string sControlName) where T: UIBehaviour
{
if (dict_allUI.ContainsKey(sControlName))
{
for (int i = 0; i < dict_allUI[sControlName].Count; i++)
{
//对应字典的值(是个集合)中,符合要求的类型的
//则返回出去,这样外部就
if (dict_allUI[sControlName][i] is T)
{
return dict_allUI[sControlName][i] as T;
}
}
}
return null;
}
/// <summary>
/// 找到相对应的UI控件并记录到字典中
/// </summary>
/// <typeparam name="T">泛型, 指UI控件</typeparam>
private void FindChildControl<T>() where T: UIBehaviour
{
T[] arr_control = this.GetComponentsInChildren<T>();
string sObjName;
for (int i = 0; i < arr_control.Length; i++)
{
sObjName = arr_control[i].gameObject.name;
if (dict_allUI.ContainsKey(sObjName))
{
dict_allUI[sObjName].Add(arr_control[i]);
}
else
{
dict_allUI.Add(sObjName, new List<UIBehaviour>() { arr_control[i] });
}
}
}
#region 让子类重写(覆盖)此方法,来实现UI的隐藏与出现
/// <summary>
/// 显示ui操作
/// </summary>
public virtual void ShowUI()
{
}
/// <summary>
/// 隐藏UI
/// </summary>
public virtual void HideUI()
{
}
#endregion
}
使用方法很简单,在UI的Canvas上挂载一个脚本继承自这个BasePanel,这样这个Canvas下面所有的UI都可以被GetControl直接找到,很方便
示例
public class UItest : BasePanel
{
private void Start()
{
GetControl<Button>("Button").onClick.AddListener(() =>
{
print("开始游戏");
});
GetControl<Button>("Button2").onClick.AddListener(() =>
{
print("设置");
});
}
}
UI层级枚举
/// <summary>
/// ui显示层级, 数值小的显示在前(根据自身需要,可扩展所需层级)
/// </summary>
public enum E_UI_Layer
{
// 提示层
Tip = 0,
// 顶层
Top = 100,
// 底层
Bot = 1000,
}
UI管理器
我们现在来编写UI管理器,首先要确定Canvas的属性来保证分辨率问题
主要是修改Canvas Scaler (画布定标器)
关于定标器的设置,可以参考
https://www.cnblogs.com/morning-lee/p/7135782.html
https://www.cnblogs.com/crazytomato/p/7832838.html
UIMaanger代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;
public class UIManager : SingletonBase<UIManager>
{
private Dictionary<string, PanelBase> dict_allPanel = new Dictionary<string, PanelBase>();
private Transform uObj_TipLayer;
private Transform uObj_TopLayer;
private Transform uObj_BotLayer;
public UIManager()
{
GameObject uObj_uiRoot = GameObject.Find("/UIRoot");
if(uObj_uiRoot == null)
{
uObj_uiRoot = ResLoadMgr.GetInstance().LoadRes<GameObject>("UI/UIRoot");
}
Transform uTrans_uiRoot = uObj_uiRoot.transform;
//创建Canvas,让其过场景的时候不被移除
GameObject.DontDestroyOnLoad(uObj_uiRoot);
//找到各层
uObj_TipLayer = uTrans_uiRoot.Find("uObj_tip");
uObj_TopLayer = uTrans_uiRoot.Find("uObj_top");
uObj_BotLayer = uTrans_uiRoot.Find("uObj_bot");
//加载EventSystem,有了它,按钮等组件才能响应
GameObject uObj_eventSystem = GameObject.Find("/EventSystem");
if(uObj_eventSystem == null)
{
uObj_eventSystem = ResLoadMgr.GetInstance().LoadRes<GameObject>("UI/EventSystem");
}
GameObject.DontDestroyOnLoad(uObj_eventSystem);
}
public void ShowPanel<T>(string sPanelName, E_UI_Layer eLayerType = E_UI_Layer.Top, UnityAction<T> callback = null) where T: PanelBase
{
//已经显示了此面板
if (dict_allPanel.ContainsKey(sPanelName))
{
//调用重写方法,具体内容自己添加
dict_allPanel[sPanelName].ShowUI();
if (callback!=null)
callback(dict_allPanel[sPanelName] as T);
return;
}
ResLoadMgr.GetInstance().LoadResAsync<GameObject>("UI/" + sPanelName, (uObj_temp) => {
//把它作为Canvas的子对象
//并且设置它的相对位置
//找到父对象
Transform uObj_father = uObj_BotLayer;
switch (eLayerType)
{
case E_UI_Layer.Tip:
uObj_father = uObj_TipLayer;
break;
case E_UI_Layer.Top:
uObj_father = uObj_TopLayer;
break;
}
//设置父对象
uObj_temp.transform.SetParent(uObj_father);
//设置相对位置和大小
uObj_temp.transform.localPosition = Vector3.zero;
uObj_temp.transform.localScale = Vector3.one;
(uObj_temp.transform as RectTransform).offsetMax = Vector2.zero;
(uObj_temp.transform as RectTransform).offsetMin = Vector2.zero;
//得到预设体身上的脚本(继承自BasePanel)
T panel_temp = uObj_temp.GetComponent<T>();
//执行外面想要做的事情
if (callback != null) {
callback(panel_temp);
}
//在字典中添加此面板
dict_allPanel.Add(sPanelName, panel_temp);
});
}
//隐藏面板
public void HidePanel(string sPanelName)
{
if (dict_allPanel.ContainsKey(sPanelName))
{
//调用重写方法,具体内容自己添加
dict_allPanel[sPanelName].HideUI();
GameObject.Destroy(dict_allPanel[sPanelName].gameObject);
dict_allPanel.Remove(sPanelName);
}
}
/// <summary>
/// 得到某一个已经显示的面板 方便外部使用
/// </summary>
public T GetPanel<T>(string sName) where T: PanelBase
{
if (dict_allPanel.ContainsKey(sName))
{
return dict_allPanel[sName] as T;
}
return null;
}
/// <summary>
/// 给控件添加自定义事件监听
/// </summary>
/// <param name="uObj_control">控件对象</param>
/// <param name="eTriggerType">事件类型</param>
/// <param name="fun_callback">事件的响应函数</param>
public static void AddCustomEventListener(UIBehaviour uObj_control, EventTriggerType eTriggerType, UnityAction<BaseEventData> fun_callback)
{
EventTrigger uObj_trigger = uObj_control.GetComponent<EventTrigger>();
if (uObj_trigger == null)
{
uObj_trigger = uObj_control.gameObject.AddComponent<EventTrigger>();
}
EventTrigger.Entry obj_entry = new EventTrigger.Entry();
obj_entry.eventID = eTriggerType;
obj_entry.callback.AddListener(fun_callback);
uObj_trigger.triggers.Add(obj_entry);
}
}
其中我们需要两个控件需要在Resources文件夹下的UI/Base路径中
其中UIRoot其实就是个Canvas,Canvas下需要包含有相对应的ui层根节点(增加新的层级,可自行扩展)
EventSystem就是UI的事件监听器,创建UI时就会创建的游戏对象。
其中涉及:
Res资源管理器: https://blog.csdn.net/hycai_007/article/details/121765347
资源包
框架资源包:
链接: https://pan.baidu.com/s/11kij_R-s3wL9-IU9WOVujw 提取码: 7eju