一、为什么要完善?
首先说说,为什么要这样做呢。
首先说下当前基类,在我们在团队配合时,可能遇到问题:
- 你当前声明的基础属性是protected的,不允许跟你配合的队友访问,那你的队友该怎样知道这些属性的值呢?
- 若你为了解决上个问题,将基础属性改为public,若你的队友是新手,有没有会误改了你的值的可能?
- 我们该基类没有继承Mono,没有Awake、OnEnable等生命周期,那我们写的虚方法Awake、OnEnable什么时候执行呢?
二、完善 BaseWindow 的思路
好,我们现在就挨个解决一下上面的问题。
1、你当前声明的基础属性是protected的,不允许跟你配合的队友访问,那你的队友该怎样知道这些属性的值呢?
我们声明如下这样的方法,队友只能得到,不能修改。
2、我们该基类没有继承Mono,没有Awake、OnEnable等生命周期,那我们写的虚方法Awake、OnEnable什么时候执行呢?
我们新增加:
打开窗体、关闭窗体、预加载窗体 等接口,供外部调用。
我们在这三个接口中,调用我们写的Awake、OnEnabl等虚方法,完成该UI窗体的初始化、关闭等生命周期。
三、最终代码
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的这些逻辑还需要我们写吗?不存在的。