一、为什么要完善?

首先说说,为什么要这样做呢。

首先说下当前基类,在我们在团队配合时,可能遇到问题:

  • 你当前声明的基础属性是protected的,不允许跟你配合的队友访问,那你的队友该怎样知道这些属性的值呢?
  • 若你为了解决上个问题,将基础属性改为public,若你的队友是新手,有没有会误改了你的值的可能?
  • 我们该基类没有继承Mono,没有Awake、OnEnable等生命周期,那我们写的虚方法Awake、OnEnable什么时候执行呢?

 

 

二、完善 BaseWindow 的思路

好,我们现在就挨个解决一下上面的问题。

 

1、你当前声明的基础属性是protected的,不允许跟你配合的队友访问,那你的队友该怎样知道这些属性的值呢?

我们声明如下这样的方法,队友只能得到,不能修改。

unity 代码多层UI嵌套无法显示_unity 代码多层UI嵌套无法显示

 

2、我们该基类没有继承Mono,没有Awake、OnEnable等生命周期,那我们写的虚方法Awake、OnEnable什么时候执行呢?

我们新增加:

打开窗体、关闭窗体、预加载窗体 等接口,供外部调用。

我们在这三个接口中,调用我们写的Awake、OnEnabl等虚方法,完成该UI窗体的初始化、关闭等生命周期。

unity 代码多层UI嵌套无法显示_虚方法_02

 

 

三、最终代码

using UnityEngine;
using UnityEngine.UI;

namespace MVCLibrary.View
{
    public class BaseWindow
    {
        //定义用到的属性(因为我们现在不继承Mono了,所以需要自己定义)

        #region 基础属性

        /// <summary>
        /// UI物体
        /// </summary>
        protected Transform transform;

        /// <summary>
        /// 资源名称(UI预制体的存放路径)
        /// </summary>
        protected string resName;

        /// <summary>
        /// 是否常驻(若不是常驻,只用一次,那么便关闭后,就将其销毁掉)
        /// </summary>
        protected bool resident;

        /// <summary>
        /// 是否可见
        /// </summary>
        protected bool visable = false;

        /// <summary>
        /// 窗体类型
        /// </summary>
        protected WindowType selfType;

        /// <summary>
        /// 场景类型
        /// </summary>
        protected SceneType sceneType;

        #endregion


        #region UI控件

        /// <summary>
        /// 按钮列表
        /// </summary>
        protected Button[] buttonList;

        #endregion


        #region 需要给子类提供的接口

        /// <summary>
        /// 初始化
        /// </summary>
        protected virtual void Awake()
        {
            buttonList = transform.GetComponentsInChildren<Button>(true);
            RegisterUiEvent();
        }

        /// <summary>
        /// UI事件的注册
        /// </summary>
        protected virtual void RegisterUiEvent()
        {
        }

        /// <summary>
        /// 添加事件
        /// </summary>
        protected virtual void OnAddListener()
        {
        }

        /// <summary>
        /// 移除事件,触发移除所有的游戏事件
        /// </summary>
        protected virtual void OnRemoveListener()
        {
        }

        /// <summary>
        /// 每次打开,触发了添加的打开事件
        /// </summary>
        protected virtual void OnEnable()
        {
        }

        /// <summary>
        /// 每次关闭,触发了添加的隐藏事件
        /// </summary>
        protected virtual void OnDisable()
        {
        }

        /// <summary>
        /// 每帧更新
        /// </summary>
        /// <param name="deltaTime">两帧间隔的时间</param>
        protected virtual void Update(float deltaTime)
        {
        }

        #endregion


        #region 窗体管理方法

        /// <summary>
        /// 打开窗体
        /// </summary>
        public void Open()
        {
            if (transform == null)
            {
                if (Create())
                    Awake();
            }

            if (transform.gameObject.activeSelf == false)
            {
                //将自身设置到 workstation 下,因为是 SetParent ,所以设置位置后,本物体层级始终在workstation最后面,就保证了本物体始终不会被其他物体遮挡。
                UIRoot.SetParent(transform, true, selfType == WindowType.TipsWindow);
                transform.gameObject.SetActive(true);
                visable = true;
                OnEnable();
                OnAddListener();
            }
        }


        /// <summary>
        /// 关闭窗体
        /// </summary>
        /// <param name="isForceClose">是否强制卸载掉(销毁)该窗体</param>
        public void Close(bool isDestroy = false)
        {
            if (transform.gameObject.activeSelf)
            {
                OnRemoveListener();
                OnDisable();

                if (isDestroy)
                {
                    if (resident)
                    {
                        transform.gameObject.SetActive(false);
                        
                        //将本UI设置到 recyclePool 回收池中
                        UIRoot.SetParent(transform,false,false);
                    }
                    else
                    {
                        GameObject.Destroy(transform.gameObject);
                        transform = null;
                    }
                }
                else
                {
                    GameObject.Destroy((transform.gameObject));
                    transform = null;
                }
            }

            visable = false;
        }

        /// <summary>
        /// 预加载窗体
        /// </summary>
        public void PreLoad()
        {
            if (transform == null)
            {
                if (Create())
                    Awake();
            }
        }

        /// <summary>
        /// 供外部调用,获得该UI的场景类型
        /// </summary>
        public SceneType GetSceneType()
        {
            return sceneType;
        }

        /// <summary>
        /// 供外部调用,获得该UI窗体类型
        /// </summary>
        public WindowType GetWindowType()
        {
            return selfType;
        }

        /// <summary>
        /// 获得该窗体根节点
        /// </summary>
        public Transform GetRoot()
        {
            return transform;
        }

        /// <summary>
        /// 获得该窗体当前是否可见
        /// </summary>
        public bool IsVisable()
        {
            return visable;
        }

        /// <summary>
        /// 获得该窗体是否常驻
        /// </summary>
        public bool GetResident()
        {
            return resident;
        }

        /// <summary>
        /// 创建UI窗体
        /// </summary>
        /// <returns>是否创建成功</returns>
        private bool Create()
        {
            if (string.IsNullOrEmpty(resName))
            {
                return false;
            }

            if (transform == null)
            {
                var obj = Resources.Load<GameObject>(resName);
                if (obj == null)
                {
                    Debug.LogError($"未找到预制件{selfType}");
                    return false;
                }

                transform = GameObject.Instantiate(obj).transform;

                transform.gameObject.SetActive(false);

                UIRoot.SetParent(transform, false, selfType == WindowType.TipsWindow);

                return true;
            }

            return true;
        }

        #endregion
    }

    /// <summary>
    /// 窗体的类型
    /// </summary>
    public enum WindowType
    {
        LoginWindow, //登录窗体
        StoreWindow, //商城窗体
        TipsWindow //提示窗体
    }

    /// <summary>
    /// 场景的类型,目的是提供根据场景类型,进行预加载
    /// </summary>
    public enum SceneType
    {
        None, //空场景
        Login, //登录场景
        Battle //对战场景
    }
}

 

现在能看出来,MVC逻辑清晰,适合团队配合,

但体量确实大,方法都要自己写,不能可视化,小项目用这样的框架确实大材小用。

 

但我们之所以能济济一堂,坐在这里,开始一场伟大的学习

不就是因为我们要升职加薪进大公司嘛

所以感谢我们的MVC框架开发者🤗

 

因为要恰饭,在此推荐下我们一个人完成的项目,可以使用DoozyUI插件进行开发,MVC的这些逻辑还需要我们写吗?不存在的。