Unity UI框架(一 窗口层级管理)

image.png

image.png

无框架容易出现的问题

多个场景会反复出现相同的UI窗体,多个场景反复加载(复用)
各个UI脚本之间的传值,容易交错,耦合度高(UI之间不相互联系,通过消息传递)
要手工控制窗体中间的层级关系(使用栈结构保持控制当前所有需要显示的UI窗体)
多个UI窗体之间相互叠加,容易出现误操作(对当前窗体遮挡处理)
窗体自动加载管理
语言的国际化

UI框架核心原则

尽量让框架本身完成与具体业务无关的事务性工作,让开发人员只需要专注游戏的业务逻辑

开发最简版
1.窗体自动加载管理
2.缓存UI窗体
3.窗体生命周期管理

UI框架的核心类设计
1.BaseUIForms基础UI窗体
2.UIManager UI窗体管理
3.UIType窗体类型
4.SysDefine 系统定义类

链接:https://pan.baidu.com/s/1-PomcmeBh2Up1S3iHWTHqQ
提取码:41cf
创建一些文件夹把贴图素材导入MyAtlas
把脚本素材分别放到

image.png

然后把Log类先注释掉
定义一个窗口参数类

/**
 *Copyright(C) 2019 by DefaultCompany
 *All rights reserved.
 *FileName:     SysDefine.cs
 *Author:       why
 *Version:      1.0
 *UnityVersion:2017.2.2f1
 *Date:         2019-05-10
 *Description:   UI框架核心参数
 * 1.系统常量
 * 2.全局性方法
 * 3.系统枚举类型
 * 4.委托定义
 *History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

#region 系统枚举类型
/// 
/// UI窗体(位置)类型
/// 
public enum UIFormType
{
    /// 
    /// 普通窗体
    /// 
    Normal,
    /// 
    /// 固定窗体
    /// 
    Fixed,
    /// 
    /// 弹出窗体
    /// 
    PopUp,
}

/// 
/// UI窗体的显示类型
/// 
public enum UIFormShowMode
{
    /// 
    /// 普通
    /// 
    Normal,
    /// 
    /// 反向切换 
    /// //按照相反方向切换过去 原路弹回来
    ReverseChange,
    /// 
    /// 隐藏其他 
    /// 
    HideOther
}

/// 
/// UI窗体透明度类型
/// 
public enum UIFormLucenyType
{
    /// 
    /// 完全透明,不能穿透
    /// 
    Lucency,
    /// 
    /// 半透明,不能穿透
    /// 
    Translucence,
    /// 
    /// 低透明度,不能穿透
    /// 
    ImPenetrable,
    /// 
    /// 可以穿透
    /// 
    Pentrate
}
#endregion
public class SysDefine
{



}

然后定义一个 UI基类

/**
 *Copyright(C) 2019 by DefaultCompany
 *All rights reserved.
 *FileName:     BaseUI.cs
 *Author:       why
 *Version:      1.0
 *UnityVersion:2017.2.2f1
 *Date:         2019-05-10
 *Description:  UI窗体父类
 *定义UI窗体的父类
 * 有四个生命周期
 * 1.Display显示状态
 * 2.Hiding隐藏状态
 * 3.ReDisplay再显示状态
 * 4.Freeze冻结状态 就是弹出窗体后面的窗体冻结
 *History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//窗体类型
public class UIType
{
    /// 
    /// 是否清空"栈集合"
    /// 
    public bool isClearStack = false;
    /// 
    /// UI窗体(位置)类型
    /// 
    public UIFormType type = UIFormType.Normal;
    /// 
    ///UI窗体显示类型
    /// 
    public UIFormShowMode mode = UIFormShowMode.Normal;
    /// 
    /// UI窗体透明度类型
    /// 
    public UIFormLucenyType lucenyType = UIFormLucenyType.Lucency;

}

public class BaseUI : MonoBehaviour
{
    UIType currentUIType { get; set; } = new UIType();

    #region 窗体的四种状态
    /// 
    /// 显示状态
    /// 
    public virtual void ActiveTrue()
    {
        gameObject.SetActive(true);
    }
    /// 
    /// 隐藏状态
    /// 
    public virtual void ActiveFalse()
    {

        gameObject.SetActive(false);
    }
    /// 
    /// 重新显示状态
    /// 
    public virtual void ReActiveTrue()
    {
        gameObject.SetActive(true);
    }

    /// 
    /// 冻结状态
    /// 
    public virtual void Freeze()
    {
        gameObject.SetActive(true);
    }
    #endregion

    #region 封装子类常用方法
    /// 
    /// 注册按钮事件
    /// 
    void RigisterBtnOnClick(string btnName,EventTriggerListener.VoidDelegate del)
    {
        Transform btn = UnityHelper.Find(gameObject.transform, btnName);
        EventTriggerListener.Get(btn?.gameObject).onClick = del;
    }

    /// 
    /// 打开UI窗体
    /// 
    /// 
    void Open(string UIName)
    {
        
    }

    /// 
    /// 关闭UI窗体
    /// 
    void Close()
    {

    }
    #endregion
}

还有一个UI管理类 先列举出字段

/**
 *Copyright(C) 2019 by DefaultCompany
 *All rights reserved.
 *FileName:     UIManager.cs
 *Author:       why
 *Version:      1.0
 *UnityVersion:2017.2.2f1
 *Date:         2019-05-10
 *Description:   UI管理器
 * 是整个UI框架的核心,用户程序通过本脚本,来实现框架绝大多数功能
 * 原则
 * 低耦合,高聚合
 * 方法单一职责
 *History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIManager : MonoBehaviour {

    /// 
    /// UI窗体预设路径 <窗口名字,路径>
    /// 
    Dictionary UIPaths;
    /// 
    /// 缓存所有UI窗体
    /// 
    Dictionary cacheUIs;
    /// 
    /// 当前显示的UI窗体
    /// 
    Dictionary showUIs;
    /// 
    /// UI根节点
    /// 
    Transform traRoot;
    /// 
    /// 全屏幕显示的节点
    /// 
    Transform traNormal;
    /// 
    /// 固定显示的节点
    /// 
    Transform traFixed;
    /// 
    /// 弹出节点
    /// 
    Transform traPopUp;
    /// 
    /// UI脚本管理节点
    /// 
    Transform traUISprites;

    private void Awake()
    {
        
    }
}

然后搭设场景


image.png

几个空节点还有UICamera
Canvans设置 为按相机照射 UIScaleMode调整为宽高比例缩放match一般是0.5或者按高度适配


image.png

相机处理设置为正交模式 照射层级只有UI 还有记得把相机往后拉一点点不然没有图片


image.png
image.png

然后再Nomal下创建这样的界面 记得定好锚点
在Resources保存为预制体 到时候动态加载


image.png

然后记得把UI相机的这个去掉


image.png

然后添加常量名字

/**
 *Copyright(C) 2019 by DefaultCompany
 *All rights reserved.
 *FileName:     SysDefine.cs
 *Author:       why
 *Version:      1.0
 *UnityVersion:2017.2.2f1
 *Date:         2019-05-10
 *Description:   UI框架核心参数
 * 1.系统常量
 * 2.全局性方法
 * 3.系统枚举类型
 * 4.委托定义
 *History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

#region 系统枚举类型
/// 
/// UI窗体(位置)类型
/// 
public enum UIFormType
{
    /// 
    /// 普通窗体
    /// 
    Normal,
    /// 
    /// 固定窗体
    /// 
    Fixed,
    /// 
    /// 弹出窗体
    /// 
    PopUp,
}

/// 
/// UI窗体的显示类型
/// 
public enum UIFormShowMode
{
    /// 
    /// 普通
    /// 
    Normal,
    /// 
    /// 反向切换 
    /// //按照相反方向切换过去 原路弹回来
    ReverseChange,
    /// 
    /// 隐藏其他 
    /// 
    HideOther
}

/// 
/// UI窗体透明度类型
/// 
public enum UIFormLucenyType
{
    /// 
    /// 完全透明,不能穿透
    /// 
    Lucency,
    /// 
    /// 半透明,不能穿透
    /// 
    Translucence,
    /// 
    /// 低透明度,不能穿透
    /// 
    ImPenetrable,
    /// 
    /// 可以穿透
    /// 
    Pentrate
}
#endregion
public class SysDefine
{
    /// 
    /// 路径常量
    /// 
    public const string canvasPath = "Canvas";
    /// 
    /// 标签常量
    /// 
    public const string canvasTag= "Canvas";
    
    //全局性方法

    //委托的定义
}

在UIManager添加UI创建方法

/**
 *Copyright(C) 2019 by DefaultCompany
 *All rights reserved.
 *FileName:     UIManager.cs
 *Author:       why
 *Version:      1.0
 *UnityVersion:2017.2.2f1
 *Date:         2019-05-10
 *Description:   UI管理器
 * 是整个UI框架的核心,用户程序通过本脚本,来实现框架绝大多数功能
 * 原则
 * 低耦合,高聚合
 * 方法单一职责
 *History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIManager : MonoBehaviour
{

    /// 
    /// UI窗体预设路径 <窗口名字,路径>
    /// 
    Dictionary UIPaths = new Dictionary();
    /// 
    /// 缓存所有UI窗体
    /// 
    Dictionary cacheUIs = new Dictionary();
    /// 
    /// 当前显示的UI窗体
    /// 
    Dictionary showUIs = new Dictionary();
    /// 
    /// UI根节点
    /// 
    Transform traRoot;
    /// 
    /// 全屏幕显示的节点
    /// 
    Transform traNormal;
    /// 
    /// 固定显示的节点
    /// 
    Transform traFixed;
    /// 
    /// 弹出节点
    /// 
    Transform traPopUp;
    /// 
    /// UI脚本管理节点
    /// 
    Transform traUISprites;

    /// 
    /// 初始化核心数据,加载"UI窗体路径"到集合中
    /// 
    private void Awake()
    {
        InitRootCanvasLoading();
        //得到UI根节点、全屏节点、固定节点、弹出节点
        traRoot = GameObject.FindGameObjectWithTag(SysDefine.canvasTag).transform;
        traNormal = traRoot.Find("Normal");
        traFixed = traRoot.Find("Fixed");
        traPopUp = traRoot.Find("PopUp");
        traUISprites = traRoot.Find("ScriptsMgr");
        //把本脚本作为"根UI窗体"的子节点 true世界坐标 false局部坐标
        this.gameObject.transform.SetParent(traUISprites, false);
        //"rootUI窗体"在场景转换时候,不允许被销毁
        DontDestroyOnLoad(traRoot);
        //初始化"UI窗体"路径信息
        UIPaths?.Add("LoginUI", "UIPrefabs/LoginUI");
    }
    /// 
    /// 打开/显示UI窗体
    /// 
    public void ShowUI(string UIName)
    {
        BaseUI baseUI;
        if (string.IsNullOrEmpty(UIName))
            return;

        baseUI = LoadUIToCacheUIs(UIName);

        if (baseUI == null)
            return;

        //根据不同的UI窗体的显示模式,分别作不同的加载处理
        switch (baseUI.currentUIType.mode)
        {
            case UIFormShowMode.Normal:
                break;
            case UIFormShowMode.ReverseChange:
                break;
            case UIFormShowMode.HideOther:
                break;
            default:
                break;
        }
    }

    /// 
    /// 初始化加载(rootUI窗体)Canvas预制体
    /// 
    private void InitRootCanvasLoading()
    {
        ResourcesMgr.GetInstance().LoadAsset(SysDefine.canvasPath, false);
    }

    #region 私有方法
    /// 
    /// 加载与判断指定的UI窗体的名字,加载到"所有UI窗体"缓存里
    /// 
    /// 
    /// 
    BaseUI LoadUIToCacheUIs(string UIName)
    {
        BaseUI baseUI;

        //得到就返回 得不到返回null
        cacheUIs.TryGetValue(UIName, out baseUI);
        if (baseUI == null)
        {
            LoadUI(UIName);
        }
        return baseUI;
    }

    /// 
    /// 根据不同位置信息,加载到root下不同的节点
    /// 
    BaseUI LoadUI(string UIName)
    {
        string uiPath;
        GameObject UIPrefabs = null;
        BaseUI baseUI = null;

        UIPaths.TryGetValue(UIName, out uiPath);
        if (!string.IsNullOrEmpty(uiPath))
        {
            UIPrefabs = ResourcesMgr.GetInstance().LoadAsset(uiPath, false);
        }

        if (traRoot != null && UIPrefabs != null)
        {
            baseUI = UIPrefabs.GetComponent();
            if (baseUI == null)
            {
                Debug.Log($"baseUI==null,请确认窗口是否有BaseUI脚本,参数:{UIName}");
                return null;
            }

            switch (baseUI.currentUIType.type)
            {
                case UIFormType.Normal:
                    UIPrefabs.transform.SetParent(traNormal, false);
                    break;
                case UIFormType.Fixed:
                    UIPrefabs.transform.SetParent(traFixed, false);
                    break;
                case UIFormType.PopUp:
                    UIPrefabs.transform.SetParent(traPopUp, false);
                    break;
            }

            UIPrefabs.SetActive(false);
            cacheUIs.Add(UIName, baseUI);
            return baseUI;
        }
        else
        {
            Debug.Log($"traRoot!=null Or UIPrefabs!=null Please Check  参数{UIName}");
        }

        Debug.Log($"出现不可预估的错误 参数{UIName}");
        return null;
    }

    /// 
    /// 把当前窗体加载到当前显示窗体集合中
    /// 
    void LoadUIToShowUIs(string UIName)
    {
        BaseUI baseUI;
        BaseUI baseUIFormCache;

        showUIs.TryGetValue(UIName, out baseUI);

        if (baseUI == null)
            return;

        cacheUIs.TryGetValue(UIName, out baseUIFormCache);

        if (baseUIFormCache != null)
        {
            showUIs.Add(UIName, baseUIFormCache);
            baseUIFormCache.ActiveTrue();
        }



    }

    #endregion
}

创建一个


image.png

挂给我们的LoginUI预制体
创一个空节点 挂上脚本


image.png

Text只有这个一句话 然后加载出来
image.png

因为没设置窗口激活所以是隐藏的


image.png

然后UI层级管理的话要用到栈 “先进后出”
Stack


image.png

类似于收盘子洗盘子 羽毛球筒放进去拿出来
还有类似于枪的弹夹

然后UIManager添加方法 有些判断写反了 又改了改

/**
 *Copyright(C) 2019 by DefaultCompany
 *All rights reserved.
 *FileName:     UIManager.cs
 *Author:       why
 *Version:      1.0
 *UnityVersion:2017.2.2f1
 *Date:         2019-05-10
 *Description:   UI管理器
 * 是整个UI框架的核心,用户程序通过本脚本,来实现框架绝大多数功能
 * 原则
 * 低耦合,高聚合
 * 方法单一职责
 *History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace UIFrameWork
{
    public class UIManager : MonoBehaviour
    {

        public static UIManager instance;
        /// 
        /// UI窗体预设路径 <窗口名字,路径>
        /// 
        Dictionary UIPaths = new Dictionary();
        /// 
        /// 缓存所有UI窗体
        /// 
        Dictionary cacheUIs = new Dictionary();
        /// 
        /// 当前显示的UI窗体
        /// 
        Dictionary showUIs = new Dictionary();
        /// 
        /// 具备 "反向切换"窗体的管理
        /// 
        Stack staUIs = new Stack();
        /// 
        /// UI根节点
        /// 
        Transform traRoot;
        /// 
        /// 全屏幕显示的节点
        /// 
        Transform traNormal;
        /// 
        /// 固定显示的节点
        /// 
        Transform traFixed;
        /// 
        /// 弹出节点
        /// 
        Transform traPopUp;
        /// 
        /// UI脚本管理节点
        /// 
        Transform traUISprites;

        /// 
        /// 初始化核心数据,加载"UI窗体路径"到集合中
        /// 
        private void Awake()
        {
            instance = this;
            InitRootCanvasLoading();
            //得到UI根节点、全屏节点、固定节点、弹出节点
            traRoot = GameObject.FindGameObjectWithTag(SysDefine.canvasTag).transform;
            traNormal = UnityHelper.Find(traRoot, SysDefine.normalNode);
            traFixed = UnityHelper.Find(traRoot, SysDefine.fixedNode);
            traPopUp = UnityHelper.Find(traRoot, SysDefine.popUpNode);
            traUISprites = UnityHelper.Find(traRoot, SysDefine.ScriptsMgrNode);
            //把本脚本作为"根UI窗体"的子节点 true世界坐标 false局部坐标
            this.gameObject.transform.SetParent(traUISprites, false);
            //"rootUI窗体"在场景转换时候,不允许被销毁
            DontDestroyOnLoad(traRoot);
            //初始化"UI窗体"路径信息
            UIPaths?.Add("LoginUI", "UIPrefabs/LoginUI");
            UIPaths?.Add("SelectUI", "UIPrefabs/SelectUI");
        }
        /// 
        /// 打开/显示UI窗体
        /// 
        public void ShowUI(string UIName)
        {
            BaseUI baseUI = null;
            if (string.IsNullOrEmpty(UIName))
                return;


            baseUI = LoadUIToCacheUIs(UIName);

            if (baseUI == null)
                return;

            //是否清空"栈集合"中得数据
            if (baseUI.currentUIType.isClearStack)
            {
                if (!ClearStack())
                    Debug.Log($"栈中数据没有成功清空请检查参数{UIName}");
            }

            //根据不同的UI窗体的显示模式,分别作不同的加载处理
            switch (baseUI.currentUIType.mode)
            {
                case UIFormShowMode.Normal:
                    LoadUIToShowUIs(UIName);
                    break;
                case UIFormShowMode.ReverseChange:
                    PushUIToStack(UIName);
                    break;
                case UIFormShowMode.HideOther:
                    EnterUIAndHideOther(UIName);
                    break;
            }
        }

        /// 
        /// 关闭(返回上一个)窗体
        /// 
        public void CloseUI(string UIName)
        {
            BaseUI baseUI;
            //参数检查
            if (string.IsNullOrEmpty(UIName))
                return;
            //所有UI窗体 没有记录直接返回
            cacheUIs.TryGetValue(UIName, out baseUI);
            if (baseUI == null)
                return;

            switch (baseUI.currentUIType.mode)
            {
                case UIFormShowMode.Normal:
                    ExitUI(UIName);
                    break;
                case UIFormShowMode.ReverseChange:
                    PopUIToStack();
                    break;
                case UIFormShowMode.HideOther:
                    ExitUIAndDisPlayOther(UIName);
                    break;
            }

        }
        #region 显示"UI管理器"内部核心数据,测试使用

        /// 
        /// 显示所有UI窗体的数量
        /// 
        /// 
        public int ShowCacheUIsCount()
        {
            return cacheUIs?.Count ?? 0;
        }
        /// 
        /// 显示当前窗体的数量
        /// 
        /// 
        public int ShowShowUIsCount()
        {
            return showUIs?.Count ?? 0;
        }
        /// 
        /// 显示栈窗体的数量
        /// 
        /// 
        public int ShowStaUIsCount()
        {
            return staUIs?.Count ?? 0;
        }
        #endregion

        #region 私有方法 
        /// 
        /// 初始化加载(rootUI窗体)Canvas预制体
        /// 
        private void InitRootCanvasLoading()
        {
            ResourcesMgr.GetInstance().LoadAsset(SysDefine.canvasPath, false);
        }

        /// 
        /// 加载与判断指定的UI窗体的名字,加载到"所有UI窗体"缓存里
        /// 
        /// 
        /// 
        BaseUI LoadUIToCacheUIs(string UIName)
        {
            BaseUI baseUI;

            //得到就返回 得不到返回null
            cacheUIs.TryGetValue(UIName, out baseUI);
            if (baseUI == null)
            {
                baseUI = LoadUI(UIName);
            }
            return baseUI;
        }

        /// 
        /// 根据不同位置信息,加载到root下不同的节点
        /// 
        BaseUI LoadUI(string UIName)
        {
            string uiPath;
            GameObject UIPrefabs = null;
            BaseUI baseUI = null;

            UIPaths.TryGetValue(UIName, out uiPath);
            if (!string.IsNullOrEmpty(uiPath))
            {
                UIPrefabs = ResourcesMgr.GetInstance().LoadAsset(uiPath, false);
            }

            if (traRoot != null && UIPrefabs != null)
            {
                baseUI = UIPrefabs.GetComponent();
                if (baseUI == null)
                {
                    Debug.Log($"baseUI==null,请确认窗口是否有BaseUI脚本,参数:{UIName}");
                    return null;
                }

                switch (baseUI.currentUIType.type)
                {
                    case UIFormType.Normal:
                        UIPrefabs.transform.SetParent(traNormal, false);
                        break;
                    case UIFormType.Fixed:
                        UIPrefabs.transform.SetParent(traFixed, false);
                        break;
                    case UIFormType.PopUp:
                        UIPrefabs.transform.SetParent(traPopUp, false);
                        break;
                }

                UIPrefabs.SetActive(false);
                cacheUIs.Add(UIName, baseUI);
                return baseUI;
            }
            else
            {
                Debug.Log($"traRoot!=null Or UIPrefabs!=null Please Check  参数{UIName}");
            }

            Debug.Log($"出现不可预估的错误 参数{UIName}");
            return null;
        }

        /// 
        /// 把当前窗体加载到当前显示窗体集合中
        /// 
        void LoadUIToShowUIs(string UIName)
        {
            BaseUI baseUI;
            BaseUI baseUIFormCache;

            showUIs.TryGetValue(UIName, out baseUI);

            if (baseUI != null)
                return;

            cacheUIs.TryGetValue(UIName, out baseUIFormCache);

            if (baseUIFormCache != null)
            {
                showUIs.Add(UIName, baseUIFormCache);
                baseUIFormCache.ActiveTrue();
            }

        }

        /// 
        /// UI窗体入栈
        /// 
        void PushUIToStack(string UIName)
        {
            BaseUI baseUI;
            //判断栈中是否有其他的窗体,有则冻结
            if (staUIs.Count > 0)
            {
                BaseUI topUI = staUIs.Peek();
                topUI.Freeze();
            }
            //判断UI所有窗体 是否有指定的UI窗体 有就处理
            cacheUIs.TryGetValue(UIName, out baseUI);
            if (baseUI != null)
            {
                baseUI.ActiveTrue();
                //把指定UI窗体,入栈
                staUIs.Push(baseUI);
            }
            else
                Debug.Log($"baseUI==null,请确认窗口是否有BaseUI脚本,参数:{UIName}");
        }

        /// 
        /// 退出指定UI窗体
        /// 
        /// 
        void ExitUI(string UIName)
        {
            BaseUI baseUI;
            //"正在显示集合"如果没有记录 则直接返回
            showUIs.TryGetValue(UIName, out baseUI);
            if (baseUI == null)
                return;
            //指定窗体,标记为隐藏状态,从正在显示集合中移除
            baseUI.ActiveFalse();
            showUIs.Remove(UIName);
        }

        /// 
        /// 反向切换 窗体的出栈处理
        /// 
        void PopUIToStack()
        {
            BaseUI baseUI = staUIs.Pop();
            baseUI.ActiveFalse();
            if (staUIs.Count >= 2)
            {
                //下一个窗体重新显示
                staUIs.Peek().ReActiveTrue();
            }
        }

        /// 
        /// 打开窗体 隐藏其他窗体
        /// 
        /// 
        void EnterUIAndHideOther(string UIName)
        {
            BaseUI baseUI;
            BaseUI baseUIFromAll;
            if (string.IsNullOrEmpty(UIName))
                return;
            showUIs.TryGetValue(UIName, out baseUI);
            if (baseUI != null)
                return;
            //把正在显示集合 栈集合都隐藏
            foreach (var item in showUIs)
            {
                item.Value.ActiveFalse();
            }

            foreach (var item in staUIs)
            {
                item.ActiveFalse();
            }

            //把当前窗体加入到"正在显示窗体"集合中,且做显示处理
            cacheUIs.TryGetValue(UIName, out baseUIFromAll);

            if (baseUIFromAll != null)
            {
                showUIs.Add(UIName, baseUIFromAll);
                baseUIFromAll.ActiveTrue();
            }
        }

        /// 
        /// 关闭窗体 显示其他窗体
        /// 
        /// 
        void ExitUIAndDisPlayOther(string UIName)
        {
            BaseUI baseUI;

            if (string.IsNullOrEmpty(UIName))
                return;
            showUIs.TryGetValue(UIName, out baseUI);
            if (baseUI == null)
                return;
            //把当前窗口失活移除
            baseUI.ActiveFalse();
            showUIs.Remove(UIName);
            //把正在显示集合 栈集合都激活
            foreach (var item in showUIs)
            {
                item.Value.ReActiveTrue();
            }

            foreach (var item in staUIs)
            {
                item.ReActiveTrue();
            }
        }

        /// 
        /// 是否清空栈集合中数据
        /// 
        /// 
        bool ClearStack()
        {
            if (staUIs != null && staUIs.Count >= 1)
            {
                staUIs.Clear();
                return true;
            }
            return false;
        }
        #endregion
    }
}

然后是把常量提取出来定义

/**
 *Copyright(C) 2019 by DefaultCompany
 *All rights reserved.
 *FileName:     SysDefine.cs
 *Author:       why
 *Version:      1.0
 *UnityVersion:2017.2.2f1
 *Date:         2019-05-10
 *Description:   UI框架核心参数
 * 1.系统常量
 * 2.全局性方法
 * 3.系统枚举类型
 * 4.委托定义
 *History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace UIFrameWork
{
    #region 系统枚举类型
    /// 
    /// UI窗体(位置)类型
    /// 
    public enum UIFormType
    {
        /// 
        /// 普通窗体
        /// //一般是全屏窗体
        Normal,
        /// 
        /// 固定窗体
        /// //一般是固定不动的 某一方向的一组图标
        Fixed,
        /// 
        /// 弹出窗体
        /// 
        PopUp,
    }

    /// 
    /// UI窗体的显示类型
    /// 
    public enum UIFormShowMode
    {
        /// 
        /// 普通  
        /// //同一层级叠加
        Normal,
        /// 
        /// 反向切换 
        /// //按照相反方向切换过去 原路弹回来
        ReverseChange,
        /// 
        /// 隐藏其他 
        /// //覆盖掉其他窗口
        HideOther
    }

    /// 
    /// UI窗体透明度类型
    /// 
    public enum UIFormLucenyType
    {
        /// 
        /// 完全透明,不能穿透
        /// 
        Lucency,
        /// 
        /// 半透明,不能穿透
        /// 
        Translucence,
        /// 
        /// 低透明度,不能穿透
        /// 
        ImPenetrable,
        /// 
        /// 可以穿透
        /// 
        Pentrate
    }
    #endregion
    public class SysDefine
    {
        // 路径常量
        public const string canvasPath = "Canvas";

        //标签常量
        public const string canvasTag = "Canvas";

        // 节点常量
        public const string normalNode = "Normal";
        public const string fixedNode = "Fixed";
        public const string popUpNode = "PopUp";
        public const string ScriptsMgrNode = "ScriptsMgr";

        //摄像机层深的常量

        //全局性方法

        //委托的定义
    }
}

我又把他的监听类 添加Transform也可以传递 语法糖改为C#6

/***
 * 
 *    Title: "SUIFW"UI框架项目
 *           主题: 事件触发监听      
 *    Description: 
 *           功能: 实现对于任何对象的监听处理。
 *    Date: 2017
 *    Version: 0.1版本
 *    Modify Recoder: 
 *    
 *   
 */
using UnityEngine;
using UnityEngine.EventSystems;

namespace UIFrameWork
{
    public class EventTriggerListener : UnityEngine.EventSystems.EventTrigger
    {
        public delegate void VoidDelegate(GameObject go);
        public VoidDelegate onClick;
        public VoidDelegate onDown;
        public VoidDelegate onEnter;
        public VoidDelegate onExit;
        public VoidDelegate onUp;
        public VoidDelegate onSelect;
        public VoidDelegate onUpdateSelect;

        /// 
        /// 得到“监听器”组件
        /// 
        /// 监听的游戏对象
        /// 
        /// 监听器
        /// 
        public static EventTriggerListener Get(GameObject go)
        {
            EventTriggerListener lister = go?.GetComponent();
            if (lister == null)
            {
                lister = go.AddComponent();
            }
            return lister;
        }
        public static EventTriggerListener Get(Transform go)
        {
            EventTriggerListener lister = go?.GetComponent();
            if (lister == null)
            {
                lister = go.gameObject.AddComponent();
            }
            return lister;
        }

        public override void OnPointerClick(PointerEventData eventData)
        {
            onClick?.Invoke(gameObject);
        }

        public override void OnPointerDown(PointerEventData eventData)
        {
            onDown?.Invoke(gameObject);
        }

        public override void OnPointerEnter(PointerEventData eventData)
        {
            onEnter?.Invoke(gameObject);
        }

        public override void OnPointerExit(PointerEventData eventData)
        {
            onExit?.Invoke(gameObject);
        }

        public override void OnPointerUp(PointerEventData eventData)
        {
            onUp?.Invoke(gameObject);
        }

        public override void OnSelect(BaseEventData eventBaseData)
        {
            onSelect?.Invoke(gameObject);
        }

        public override void OnUpdateSelected(BaseEventData eventBaseData)
        {
            onUpdateSelect?.Invoke(gameObject);
        }

    }//Class_end
}

UI基类封装常用方法

/**
 *Copyright(C) 2019 by DefaultCompany
 *All rights reserved.
 *FileName:     BaseUI.cs
 *Author:       why
 *Version:      1.0
 *UnityVersion:2017.2.2f1
 *Date:         2019-05-10
 *Description:  UI窗体父类
 *定义UI窗体的父类
 * 有四个生命周期
 * 1.Display显示状态
 * 2.Hiding隐藏状态
 * 3.ReDisplay再显示状态
 * 4.Freeze冻结状态 就是弹出窗体后面的窗体冻结
 *History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace UIFrameWork
{
    //窗体类型
    public class UIType
    {
        /// 
        /// 是否清空"栈集合" 反向切换
        /// 
        public bool isClearStack = false;
        /// 
        /// UI窗体(位置)类型
        /// 
        public UIFormType type = UIFormType.Normal;
        /// 
        ///UI窗体显示类型
        /// 
        public UIFormShowMode mode = UIFormShowMode.Normal;
        /// 
        /// UI窗体透明度类型
        /// 
        public UIFormLucenyType lucenyType = UIFormLucenyType.Lucency;

    }

    public class BaseUI : MonoBehaviour
    {
        public UIType currentUIType { get; set; } = new UIType();

        #region 窗体的四种状态
        /// 
        /// 显示状态
        /// 
        public virtual void ActiveTrue()
        {
            gameObject.SetActive(true);
        }
        /// 
        /// 隐藏状态
        /// 
        public virtual void ActiveFalse()
        {

            gameObject.SetActive(false);
        }
        /// 
        /// 重新显示状态
        /// 
        public virtual void ReActiveTrue()
        {
            gameObject.SetActive(true);
        }

        /// 
        /// 冻结状态
        /// 
        public virtual void Freeze()
        {
            gameObject.SetActive(true);
        }
        #endregion

        #region 封装子类常用方法
        /// 
        /// 注册按钮事件
        /// 
        protected void RigisterBtnOnClick(string btnName, EventTriggerListener.VoidDelegate del)
        {
            Transform btn = UnityHelper.Find(gameObject.transform, btnName);
            EventTriggerListener.Get(btn?.gameObject).onClick = del;
        }

        /// 
        /// 打开UI窗体
        /// 
        /// 
        protected void OpenUI(string UIName)
        {
            UIManager.instance.ShowUI(UIName);
        }

        /// 
        /// 关闭UI窗体
        /// 
        protected void CloseUI()
        {
            string UIName;
            //int intPos = -1;
            //命名空间+类名
            UIName = GetType().ToString();
            //查询第一次出现在这在第几位
            //intPos = UIName.IndexOf('.');

            //if (intPos != -1)
            //{
            //    UIName = UIName.Substring(intPos + 1);
            //}

            UIManager.instance.CloseUI(UIName);

        }
        #endregion
    }
}

提供一个方法类Find Add的封装

/**
 *Copyright(C) 2019 by DefaultCompany
 *All rights reserved.
 *FileName:     UnityHelper.cs
 *Author:       why
 *Version:      1.0
 *UnityVersion:2017.2.2f1
 *Date:         2019-05-10
 *Description:  Unity帮助脚本
 * 提供程序用户一些常用功能方法实现,方便程序员快速开发
 *History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace UIFrameWork
{
    public class UnityHelper
    {
        /// 
        /// 递归查找子结点
        /// 
        /// 
        public static Transform Find(Transform parent, string childName)
        {
            Transform child = null;

            child = parent.transform.Find(childName);
            if (child == null)
            {
                //直接是所有子物体对象
                foreach (Transform item in parent)
                {
                    child = Find(item, childName);
                    if (child != null)
                        return child;
                }
            }
            return child;
        }

        /// 
        /// 获取子节点对象的脚本 限定范围游戏对象的组件
        /// 
        /// 
        /// 
        /// 
        /// 
        public static T GetComponent(Transform parent, string childName) where T : Component
        {
            Transform child = null;
            child = Find(parent, childName);

            return child?.gameObject.GetComponent();
        }

        /// 
        /// 给子节点添加脚本
        /// 
        /// 
        /// 
        /// 
        /// 
        public static T AddComponent(Transform parent, string childName) where T : Component
        {
            Transform child = null;
            child = Find(parent, childName);

            //如果有相同的脚本,则先删除
            T[] componentScriptsArray = child.GetComponents();
            for (int i = 0; i < componentScriptsArray.Length; i++)
            {
                GameObject.Destroy(componentScriptsArray?[i]);
            }
            return child?.gameObject.AddComponent();
        }

        /// 
        /// 给子节点设置父对象
        /// 
        /// 
        /// 
        public static void SetParent(Transform parent, Transform child)
        {
            //如果为真,则修改父级相对位置、比例和旋转,以便
            //对象保持与以前相同的世界空间位置、旋转和缩放。
            child.SetParent(parent, false);
            child.localPosition = Vector3.zero;
            child.localScale = Vector3.one;
            child.localEulerAngles = Vector3.zero;
        }

    }
}

然后拿去测试
这里定义一些窗口的常量定义

/**
 *Copyright(C) 2019 by DefaultCompany
 *All rights reserved.
 *FileName:     ProConst.cs
 *Author:       why
 *Version:      1.0
 *UnityVersion:2018.3.9f1
 *Date:         2019-05-12
 *Description:   项目中常量定义
 *History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ProConst 
{
    //常量定义 UI窗体名
    public const string LoginUI = "LoginUI";
    public const string SelectUI = "SelectUI";
    

}

登录逻辑

/**
 *Copyright(C) 2019 by DefaultCompany
 *All rights reserved.
 *FileName:     LoginUI.cs
 *Author:       why
 *Version:      1.0
 *UnityVersion:2018.3.9f1
 *Date:         2019-05-11
 *Description:   登录窗体
 *History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UIFrameWork;
public class LoginUI : BaseUI
{
    public void Awake()
    {
        //定义窗口性质 (默认数值)
        currentUIType.type = UIFormType.Normal;
        currentUIType.mode = UIFormShowMode.Normal;
        currentUIType.lucenyType = UIFormLucenyType.Lucency;

        //注册按钮
        RigisterBtnOnClick("btnLogin", LogonSys);
    }

    public void LogonSys(GameObject go)
    {
        //前台或者后台检查用户名称与密码

        //如果成功,则登录下一个窗口
        OpenUI(ProConst.SelectUI);
    }
}

人物选择界面逻辑

/**
 *Copyright(C) 2019 by DefaultCompany
 *All rights reserved.
 *FileName:     SelectUI.cs
 *Author:       why
 *Version:      1.0
 *UnityVersion:2018.3.9f1
 *Date:         2019-05-11
 *Description:   选择英雄窗体
 *History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UIFrameWork;
public class SelectUI :BaseUI
{
    private void Awake()
    {
        //定义窗口性质 (默认数值)
        currentUIType.mode = UIFormShowMode.HideOther;
        //进入主城
        RigisterBtnOnClick("BtnConfirm", go =>Debug.Log("进入主城"));
        //返回方法
        RigisterBtnOnClick("BtnClose", go => CloseUI());
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}
image.png

拖一个选择界面


image.png

主城还没做 只有个Deg提示
然后可以来回切换
脚本这么放


image.png

你可能感兴趣的:(Unity UI框架(一 窗口层级管理))