七、UI管理器

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值