前言
- 我知道对于界面而言,有个框架会事半功倍
- 我看了siki的ui框架视频,借鉴了其中的思路,自己写了一下
- 最后当然是完美完成了。哈哈哈
- 记录一下遇到的一些问题和解决办法
思路
- 在Canvas上面有个UIManager 管理类负责统一的加载和销毁
- 每个面板都有一个生命周期事件脚本
- 生命周期 被加载—在栈顶——在下面——被关闭——被销毁
- 当页面被点击的时候,实例化相应的面板,并加载进UIManager中的栈里面。执行元素的栈顶事件和被加载事件,对于栈顶元素,则执行在下面事件
- 当页面被关闭的时候,就取出栈顶元素,并执行关闭事件。就是禁用
问题— 预制体无法和场景的元素产生关联
- 由于加载和关闭函数都在UIManager类中
- 我一开始想通过面板拖拽给面板预制体的点击事件添加方法
- 可是Canvas在场景中,无法关联,事件总是丢失
- 解决思路 由于每个面板都有生命周期事件,所以通过中介者模式,获得管理类的引用,调用其中的方法即可
问题二 加载顺序问题
- 我们在实例化生成面板对象后,立马就要调用生命周期方法。
- Start函数执行顺序在这些方法后面,会导致某些元素还没获取
- 应该将获取元素放置在Awake方法中
问题三 点击问题
- 每个UI面板元素都有一个canvas group组件 通过调节Alpha值和 Block RaycastHit来设定透明值和能否被射线检测到
如果一个物体被隐藏了,sendMessage是没有办法起到作用的
代码如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum PanelType
{
BagInfo,
BageInfo2,
EquipPanel,
MainMenu,
SinglePerson,
SystemOption,
UseEquip
}
public class UIManager : MonoBehaviour {
public static UIManager instance;
private Stack<GameObject> panelStack = new Stack<GameObject>();
private const string path = "Panels";
private Dictionary<string, GameObject> panelDic = new Dictionary<string, GameObject>();
//类似于一个池子
private Dictionary<string, GameObject> panelDic2 = new Dictionary<string, GameObject>();
private UIManager() { }
private void Awake()
{
instance = this;
}
private void Start()
{
//获取所有页面
GameObject[] panelObjects = Resources.LoadAll<GameObject>(path);
foreach (var item in panelObjects)
{
panelDic.Add(item.name, item);
}
LoadPanels("MainMenu");
}
/// <summary>
/// 加载页面
/// </summary>
/// <param name="panelName"></param>
public void LoadPanels(string panelName)
{
if (!panelDic.ContainsKey(panelName)) Debug.LogError("输入的页面名字错误");
GameObject tempTop = null;
if (!panelDic2.ContainsKey(panelName))
{
tempTop = GameObject.Instantiate<GameObject>(panelDic[panelName], transform);
panelDic2.Add(panelName, tempTop);
}
else
{
tempTop = panelDic2[panelName];
}
PanelLifeTime lifeControl = tempTop.GetComponent<PanelLifeTime>();
//如果是第一次加载,就启动loading事件
if (lifeControl.FirstLoad)
{
lifeControl.OnLoading();
lifeControl.FirstLoad = false;
}
if (panelStack.Count != 0)
{
panelStack.Peek().SendMessage("OnBack"); //被遮挡
}
lifeControl.OnTop();
panelStack.Push(tempTop);
}
/// <summary>
/// 卸载页面
/// </summary>
/// <param name="panelName"></param>
public void UnLoadPanels()
{
GameObject obj = panelStack.Pop();
obj.SendMessage("OnClose");
if (panelStack.Count != 0)
{
panelStack.Peek().SendMessage("OnTop");
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 生命周期事件脚本
/// </summary>
public class PanelLifeTime : MonoBehaviour {
private CanvasGroup group;
private bool firstLoad = true;
public bool FirstLoad
{
get
{
return firstLoad;
}
set
{
firstLoad = value;
}
}
private void Awake()
{
group = gameObject.GetComponent<CanvasGroup>();
}
/// <summary>
/// 被加载
/// </summary>
public void OnLoading()
{
}
/// <summary>
/// 被遮挡
/// </summary>
public void OnBack()
{
group.blocksRaycasts = false;
group.alpha = 0.5f;
}
/// <summary>
/// 在顶部
/// </summary>
public void OnTop()
{
if (group != null)
{
gameObject.SetActive(true);
group.blocksRaycasts = true;
group.alpha = 1;
}
else
{
Debug.Log("hello problem");
}
}
/// <summary>
/// 关闭时
/// </summary>
public void OnClose()
{
gameObject.SetActive(false);
}
public void OnCLick(string panelName)
{
UIManager.instance.LoadPanels(panelName);
}
public void OnCloseButtonDown()
{
UIManager.instance.UnLoadPanels();
}
}