Unity 简易UI框架

加载逻辑可以参考下面这篇文章Unity AssetBundle合并颗粒打包与加载_小张不爱写代码的博客-CSDN博客_unity assetbundle打包颗粒度

 创建两个枚举如下

/// <summary>
/// UI窗体透明度类型
/// </summary>
public enum UIFormLucenyType
{
    /// <summary>
    /// 完全透明
    /// </summary>
    Lucency,
    /// <summary>
    /// 半透明
    /// </summary>
    Translucence,
    /// <summary>
    /// 低透明
    /// </summary>
    ImPenetrable,
    /// <summary>
    /// 纯黑
    /// </summary>
    Opacification,
}

/// <summary>
/// UI窗体层级
/// </summary>
public enum UILayer
{
    /// <summary>
    /// 基础层 大厅、登录等基础界面 0-100
    /// </summary>
    NormalLayer = 0,
    /// <summary>
    /// 二级弹窗 例如商城  背包等等  101-200
    /// </summary>
    TwoPopLayer = 101,
    /// <summary>
    /// 三级弹窗 例如 跑马灯、弹窗奖励  二次确认弹窗等等 201-300
    /// </summary>
    ThreePopLayer = 201,
    /// <summary>
    /// 四级弹窗 例如 断网重连 之类的  301-400
    /// </summary>
    FourPopLayer = 301,
}

在创建一个脚本Tool.cs

using UnityEngine;

public class Tools
{
    /// <summary>
    /// 创建物体
    /// </summary>
    /// <param name="obj">原物体</param>
    /// <param name="parent">父节点</param>
    /// <param name="isRecover">是否重置大小坐标</param>
    /// <param name="isOffset">是否重置UI偏移</param>
    public static GameObject LocalInstantiate(GameObject obj,Transform parent = null,bool isRecover = true,bool isOffset = false)
    {
        GameObject o = GameObject.Instantiate(obj);
        if (parent)
            o.transform.parent = parent;
        if (isRecover)
        {
            SetRecover(o,isOffset);
        }
        return o;
    }

    /// <summary>
    /// 重置数据
    /// </summary>
    /// <param name="o"></param>
    public static void SetRecover(GameObject o,bool isOffset = false)
    {
        if (o == null) return;
        o.transform.localPosition = Vector3.zero;
        o.transform.localScale = Vector3.one;
        if (isOffset)
        {
            RectTransform rect = o.GetComponent<RectTransform>();
            if (rect)
            {
                rect.offsetMax = new Vector2(0, 0);
                rect.offsetMin = new Vector2(0, 0);
            }
        }
    }

    /// <summary>
    /// 查找物体
    /// </summary>
    /// <param name="parent"></param>
    /// <param name="path"></param>
    /// <returns></returns>
    public static Transform FindChild(GameObject parent,string path)
    {
        if (parent == null || path == "") return null;
        return parent.transform.Find(path);
    }
}

创建一个UI的基类UIBase.cs 所有的UI都继承自此脚本

using DG.Tweening;
using System;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// UI基类
/// </summary>
public class UIBase : MonoBehaviour
{
    /// <summary>
    /// UI窗体透明度类型
    /// </summary>
    [Header("UI窗体透明度类型")]
    public UIFormLucenyType UIForm_LucenyType = UIFormLucenyType.Translucence;
    /// <summary>
    /// UI窗体透明度类型
    /// </summary>
    [Header("UI窗体层级")]
    public UILayer m_UILayer = UILayer.NormalLayer;
    /// <summary>
    /// UI数据
    /// </summary>
    public object[] m_Data;
    /// <summary>
    /// 存储所有注册的事件ID 用来关闭UI时清除消息监听
    /// </summary>
    private List<int> m_EventIDs;
    /// <summary>
    /// UI打开之后播放的动画效果
    /// </summary>
    public virtual void ShowAnim()
    {
        transform.DOScale(new Vector3(1.02f, 1.02f, 1.02f), 0.2f).OnComplete(() =>
        {
            transform.DOScale(Vector3.one, 0.1f).OnComplete(() =>
            {
                this.OnShow();
            });
        });
    }

    /// <summary>
    /// UI刚刚加载出来回调
    /// </summary>
    public virtual void OnLoad(object[] data)
    {
        this.m_EventIDs = new List<int>();
        this.m_Data = data;
        //UI动画播放完动画之后做的处理
        this.ShowAnim();
    }

    /// <summary>
    /// UI加载完毕并且动画播放完之后的回调
    /// </summary>
    public virtual void OnShow()
    {
        //UI打开完毕之后注册消息
        this.OnRegister();
    }

    /// <summary>
    /// UI注册消息
    /// </summary>
    public virtual void OnRegister()
    {
        
    }

    /// <summary>
    /// 注册消息
    /// </summary>
    /// <param name="eventID"></param>
    /// <param name="bindFunc"></param>
    public void AddRegister(int eventID, OnActionHandler bindFunc)
    {
        this.m_EventIDs.Add(eventID);
        EventDispatcher.AddEventListener(this, eventID, bindFunc);
    }

    public virtual void OnHide()
    {
        this.gameObject.SetActive(false);
    }

    /// <summary>
    /// 关闭UI
    /// </summary>
    public virtual void OnClose()
    {
        EventDispatcher.RemoveEventListener(this,this.m_EventIDs.ToArray());
    }
}

在创建一个UI管理器

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;
public class UIMgr : MonoBehaviour
{
    public static UIMgr Ins;
    /// <summary>
    /// 缓存所有的UI窗体
    /// </summary>
    private Dictionary<string, UIBase> m_AllUI;
    /// <summary>
    /// UI根节点
    /// </summary>
    private GameObject _Root = null;
    /// <summary>
    /// Canvas
    /// </summary>
    public Transform _CanvasTran = null;
    /// <summary>
    /// UI节点
    /// </summary>
    private Transform _TraNormal = null;
    /// <summary>
    /// 遮罩节点
    /// </summary>
    private Image _MaskNode = null;
    /// <summary>
    /// 栈 结构表示的是 当前弹出的ui窗体的集合
    /// </summary>
    private Stack<UIBase> _StaCurrentUIbase;
    #region 初始化
    private void Awake()
    {
        DontDestroyOnLoad(this);
        Ins = this;
        this.Init();
    }

    void Init()
    {
        _StaCurrentUIbase = new Stack<UIBase>();
        m_AllUI = new Dictionary<string, UIBase>();
        //加载UI根节点
        _CanvasTran = GameObject.Find("Canvas").transform;
        GameObject o = AssetBundleMgr.Ins.LoadAsset<GameObject>("ui_uiroot", "uiroots", FileType.OBJ);
        _Root = Tools.LocalInstantiate(o, _CanvasTran, true, true);
        //拿到节点下的UI节点
        _TraNormal = Tools.FindChild(_Root, "normal");
        _MaskNode = Tools.FindChild(_Root, "mask").GetComponent<Image>();
    }
    #endregion
    #region 供外部调用接口
    /// <summary>
    /// 打开UI
    /// </summary>
    /// <param name="uiname">ui名字</param>
    /// <param name="uimodule">ui预制体放置的模块</param>
    /// <param name="data">打开UI后要传递的参数</param>
    public void Show(string uiname, string uimodule = "ui_base", params object[] data)
    {
        //UI已激活则不处理
        if (this.Exists(uiname) != null) return;
        if (string.IsNullOrEmpty(uiname) || string.IsNullOrEmpty(uimodule)) return;
        //UI窗体基类
        UIBase baseUI = this.LoadUI(uiname, uimodule, data);
        if (baseUI == null) return;
        //遮罩
        this.ShowMask(baseUI);
        if(baseUI.m_UILayer != UILayer.NormalLayer)
        {
            //添加UI层
            DepthUI dep = baseUI.gameObject.AddComponent<DepthUI>();
            dep.SetLayer(baseUI.m_UILayer);
            //将2级弹窗及以上全部加入到栈中
            _StaCurrentUIbase.Push(baseUI);
        }
        //UI刚创建出来之后做的处理
        baseUI.OnLoad(data);
    }
    /// <summary>
    /// 关闭UI
    /// </summary>
    /// <param name="uiname">ui名字</param>
    public void Close(string uiname)
    {
        //UI窗体基类
        UIBase baseUI = null;
        if (string.IsNullOrEmpty(uiname)) return;
        //所有UI窗体缓存如果没有记录,则直接返回。
        this.m_AllUI.TryGetValue(uiname, out baseUI);
        if (baseUI == null) return;
        //将栈顶UI出栈 ui遮罩切换到上一层ui
        this.PopUIForms();
        baseUI.OnClose();
        //删除之前清除自身动画
        baseUI.gameObject.transform.DOKill();
        GameObject.Destroy(baseUI.gameObject);
        m_AllUI.Remove(uiname);
    }

    /// <summary>
    /// 检查该UI是否处于开启状态
    /// </summary>
    /// <param name="uiname"></param>
    /// <returns></returns>
    public UIBase Exists(string uiname)
    {
        UIBase baseUI = null;
        //获取该窗口信息
        m_AllUI.TryGetValue(uiname, out baseUI);
        return baseUI;
    }
    #endregion

    #region 内部调用接口
    /// <summary>
    /// 加载UI
    /// </summary>
    /// <param name="uiname">UI窗体名称</param>
    /// <param name="uimodule">ui模块</param>
    /// <param name="data">ui传递的数据</param>
    private UIBase LoadUI(string uiname, string uimodule = "ui_base", params object[] data)
    {
        UIBase baseui = null;
        GameObject goCloneUIPrefabs = Instantiate(AssetBundleMgr.Ins.LoadAsset<GameObject>(uimodule, uiname, FileType.OBJ));
        if (_Root != null && goCloneUIPrefabs != null)
        {
            baseui = goCloneUIPrefabs.GetComponent<UIBase>();
            if (baseui == null)
            {
                Debug.Log("baseui==null uiname=" + uiname);
                baseui = goCloneUIPrefabs.AddComponent<UIBase>();
            }
            goCloneUIPrefabs.transform.SetParent(_TraNormal);
            Tools.SetRecover(goCloneUIPrefabs);
            m_AllUI.Add(uiname, baseui);
            return baseui;
        }
        Debug.Log("Load error uiFormName=" + uiname);
        return null;
    }
    /// <summary>
    /// 显示遮罩
    /// </summary>
    /// <param name="baseui"></param>
    private void ShowMask(UIBase baseui)
    {
        if (_MaskNode == null || baseui == null)
        {
            if (_MaskNode != null)
            {
                _MaskNode.transform.parent = _Root.transform;
                _MaskNode.gameObject.SetActive(false);
            }
            return;
        }
        _MaskNode.gameObject.SetActive(true);
        _MaskNode.transform.parent = baseui.transform;
        _MaskNode.transform.SetAsFirstSibling();
        switch (baseui.UIForm_LucenyType)
        {
            case UIFormLucenyType.Lucency:
                Debug.Log("==== 完全透明");
                _MaskNode.color = new Color(0, 0, 0, 0f / 255f);
                break;
            case UIFormLucenyType.Translucence:
                Debug.Log("==== 半透明");
                _MaskNode.color = new Color(0, 0, 0, 50f / 255f);
                break;
            case UIFormLucenyType.ImPenetrable:
                Debug.Log("==== 低透明");
                _MaskNode.color = new Color(0, 0, 0, 200f / 255f);
                break;
            case UIFormLucenyType.Opacification:
                Debug.Log("==== 纯黑");
                _MaskNode.color = new Color(0, 0, 0, 255f);
                break;
            default:
                break;
        }
    }
    /// <summary>
    /// UI窗体出栈逻辑
    /// </summary>
    private void PopUIForms()
    {
        //出栈窗体的下一个窗体逻辑
        UIBase nextuibase = null;
        if (_StaCurrentUIbase.Count >= 2)
        {
            //出栈逻辑
            UIBase uibase = _StaCurrentUIbase.Pop();
            //出栈的窗体,进行隐藏处理
            uibase.OnHide();
            //获取栈顶元素
            nextuibase = _StaCurrentUIbase.Peek();
        }
        else if (_StaCurrentUIbase.Count == 1)
        {
            //出栈
            UIBase uibase = _StaCurrentUIbase.Pop();
            //出栈的窗体,进行隐藏处理
            uibase.OnHide();
        }
        this.ShowMask(nextuibase);
    }
    #endregion
}

 在创建一个事件管理类EventDispatcher.cs

using System.Collections.Generic;
using System.Linq;
/// <summary>
/// 委托原型
/// </summary>
/// <param name="obj"></param>
public delegate void OnActionHandler(params object[] obj);
public class EventDispatcher
{
    #region 消息ID
    public static int Test = 10001;
    public static int Test01 = 10002;
    #endregion
    /// <summary>
    /// 监听字典
    /// </summary>
    private static Dictionary<int, List<EventStruct>> events;
    /// <summary>
    /// 添加监听
    /// </summary>
    /// <param name="baseui"></param>
    /// <param name="eventID"></param>
    /// <param name="onAction"></param>
    public static void AddEventListener(UIBase baseui,int eventID, OnActionHandler onAction)
    {
        if(events == null)events = new Dictionary<int, List<EventStruct>>();
        EventStruct ev = new EventStruct();
        ev.m_Baseui = baseui;
        ev.m_Func = onAction;
        if (!events.ContainsKey(eventID))
        {
            events.Add(eventID, new List<EventStruct>() { ev });
        }
        else
        {
            List<EventStruct> list = events[eventID];
            bool b = false;
            for (int i = 0; i < list.Count; i++)
            {
                if (list[i].m_Baseui == baseui)
                {
                    b = true;
                    break;
                }
            }
            if (!b)
            {
                list.Add(ev);
                events[eventID] = list;
            }
        }
    }

    /// <summary>
    /// 移除监听
    /// </summary>
    /// <param name="baseui"></param>
    /// <param name="eventIDs"></param>
    public static void RemoveEventListener(UIBase baseui, int[] eventIDs)
    {
        if (events == null) return;
        if (eventIDs != null && eventIDs.Length > 0)
        {
            for (int i = 0; i < eventIDs.Length; i++)
            {
                List<EventStruct> ls = events[eventIDs[i]];
                for (int j = 0; j < ls.Count; j++)
                {
                    if (ls[j].m_Baseui == baseui)
                    {
                        ls.RemoveAt(j);
                        break;
                    }
                }
                if (ls.Count <= 0)
                {
                    events.Remove(eventIDs[i]);
                }
                else
                {
                    events[eventIDs[i]] = ls;
                }
            }
        }
    }

    /// <summary>
    /// 消息派发
    /// </summary>
    /// <param name="eventID">监听ID</param>
    /// <param name="data">参数</param>
    public static void Dispatcher(int eventID, params object[] data)
    {
        if (events == null) return;
        if (events.ContainsKey(eventID))
        {
            List<EventStruct> list = events[eventID];
            for (int i = 0; i < list.Count; i++)
            {
                if (list[i] != null)
                {
                    list[i].m_Func(data);
                }
            }
        }
    }
}
public class EventStruct
{
    public OnActionHandler m_Func;
    public UIBase m_Baseui;
}

创建一个DepthUI.cs

using UnityEngine;
using UnityEngine.UI;

public class DepthUI : MonoBehaviour
{
    public int order = 0;
    public bool isUi = true;

    public void SetLayer(UILayer layer, bool isUi = true)
    {
        this.order = (int)layer;
        if (isUi)
        {
            Canvas canvas = this.GetComponent<Canvas>();
            if (canvas == null)
            {
                canvas = this.gameObject.AddComponent<Canvas>();
                this.gameObject.AddComponent<GraphicRaycaster>();
            }
            canvas.overrideSorting = true;
            canvas.sortingOrder = order;
        }
        else
        {
            Renderer[] renders = this.GetComponentsInChildren<Renderer>();
            foreach (Renderer render in renders)
            {
                render.sortingOrder = order;
            }
        }
    }
}

创建一个测试脚本Demo.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Demo : MonoBehaviour
{
    public AudioSource audio;
    public Transform tran;
    // Start is called before the first frame update
    void Start()
    {
        this.gameObject.AddComponent<AssetBundleMgr>();
        //bundle加载
        //AssetBundleManager.Ins.InitModel(AssetLoadMode.AssetBundler);
        //Editor加载
        AssetBundleMgr.Ins.InitModel(AssetLoadMode.Editor);
        this.gameObject.AddComponent<UIMgr>();
        #region 测试数据
        //异步
        //AssetBundleManager.Ins.LoadAsyncAsset<AudioClip>("audio_man", "bg", FileType.MP3, (obj) =>
        //{
        //    audio.clip = obj;
        //    audio.Play();
        //});
        //同步
        //AudioClip o = AssetBundleManager.Ins.LoadAsset<AudioClip>("audio_man", "bg", FileType.MP3);
        //audio.clip = o;
        //audio.Play();

        //异步
        //AssetBundleManager.Ins.LoadAsyncAsset<GameObject>("ui_common", "card", FileType.OBJ, (obj) =>
        //{
        //    obj = Instantiate(obj);
        //    obj.transform.parent = tran;
        //    obj.transform.localPosition = Vector3.zero;
        //    obj.GetComponent<RectTransform>().anchoredPosition = Vector2.zero;
        //});
        #endregion
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.W))
        {
            UIMgr.Ins.Show("card", "ui_common");
        }
        if (Input.GetKeyDown(KeyCode.Space))
        {
            UIMgr.Ins.Close("card");
        }


        if (Input.GetKeyDown(KeyCode.E))
        {
            UIMgr.Ins.Show("gamemain", "ui_gamemain");
        }
        if (Input.GetKeyDown(KeyCode.R))
        {
            UIMgr.Ins.Close("gamemain");
        }


        if (Input.GetKeyDown(KeyCode.A))
        {
            UIMgr.Ins.Show("gameover", "ui_gameover", "zyt");
        }
        if (Input.GetKeyDown(KeyCode.S))
        {
            UIMgr.Ins.Close("gameover");
        }

        if (Input.GetKeyDown(KeyCode.Y))
        {
            EventDispatcher.Dispatcher(EventDispatcher.Test);
            EventDispatcher.Dispatcher(EventDispatcher.Test01);
        }
        if (Input.GetKeyDown(KeyCode.U))
        {
            EventDispatcher.Dispatcher(EventDispatcher.Test,1,2,3,"sssss");
            EventDispatcher.Dispatcher(EventDispatcher.Test01,4,5,6,"bbbb");
        }
    }
}

测试结果如下

 

如下是root节点内容 

 

猜你喜欢

转载自blog.csdn.net/qq_41973169/article/details/128292381