0
点赞
收藏
分享

微信扫一扫

JavaScript基础(十二)

慎壹 2024-06-12 阅读 6

在这里插入图片描述


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

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

👨‍💻 本文由 秩沅 原创

👨‍💻 收录于专栏

🅰️



文章目录


前言


🎶(W 面板基类


相关知识点


在这里插入图片描述

特点


  • 方便子类面板继承,并且可以获取面板中的控件脚本进行操作
  • 为一切面板类封装好了相同的方法
    在这里插入图片描述

脚本


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自定义设置父类层级
    在这里插入图片描述

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

  • EventSystem也连带作为预制体
    在这里插入图片描述

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;
    }

    /// <summary>
    /// 显示面板
    /// </summary>
    /// <typeparam name="T">面板脚本类型</typeparam>
    /// <param name="panelName">面板名</param>
    /// <param name="layer">显示在哪一层</param>
    /// <param name="callBack">当面板预设体创建成功后 你想做的事</param>
    
    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;
    }

    /// <summary>
    /// 给控件添加自定义事件监听
    /// </summary>
    /// <param name="control">控件对象</param>
    /// <param name="type">事件类型</param>
    /// <param name="callBack">事件的响应函数</param>
    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 管理器优化——自定义事件监听


特点

为什么要添加?

  • 自定义事件的添加
  • 原型如下,但我们的优化是完全用到代码添加自定义事件组件
    在这里插入图片描述
脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;

/// <summary>
/// UI层级
/// </summary>
public enum E_UI_Layer
{
    Bottom,
    Midle,
    Top,
    System,
}

/// <summary>
/// UI管理器
/// 1.管理所有显示的面板
/// 2.提供给外部 显示和隐藏等等接口
/// </summary>
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);
    }

    /// <summary>
    /// 通过层级枚举 得到对应层级的父对象
    /// </summary>
    /// <param name="layer"></param>
    /// <returns></returns>
    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;
    }

    /// <summary>
    /// 显示面板
    /// </summary>
    /// <typeparam name="T">面板脚本类型</typeparam>
    /// <param name="panelName">面板名</param>
    /// <param name="layer">显示在哪一层</param>
    /// <param name="callBack">当面板预设体创建成功后 你想做的事</param>
    
    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);
        });
    }

    /// <summary>
    /// 隐藏面板
    /// </summary>
    /// <param name="panelName"></param>
    public void HidePanel(string panelName)
    {
        if(panelContorlDic .ContainsKey(panelName))
        {           
            panelContorlDic[panelName].HideMe();
            GameObject.Destroy(panelContorlDic[panelName].gameObject);
            panelContorlDic.Remove(panelName);
        }
    }

    /// <summary>
    /// 得到某一个已经显示的面板 方便外部使用
    /// </summary>
    public T GetPanel<T>(string name) where T:BasePanel
    {
        if (panelContorlDic .ContainsKey(name))
            return panelContorlDic[name] as T;
        return null;
    }

    /// <summary>
    /// 给控件添加自定义事件监听
    /// </summary>
    /// <param name="control">控件对象</param>
    /// <param name="type">事件类型</param>
    /// <param name="callBack">事件的响应函数</param>
    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#专题篇】—核心章题单实践练习


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


在这里插入图片描述


举报

相关推荐

0 条评论