UI管理器
用于显示面板,隐藏面板,添加自定义事件。
1.怎样能存储所有面板? ———— 字典,面板名为Key , 面板基类为Value
2.怎样在字典中存储不同面板脚本 ———— 所有面板继承面板基类,用里氏替换在字典中记录
构造函数:进行初始化加载Canvas和EventSystem
显示面板:如果字典中已经存在该面板,则直接执行面板显示后的逻辑,否则先异步加载面板,然后初始化该面板,再加入字典。
隐藏面板:如果字典存在该面板,则执行对应面板逻辑后直接销毁并从字典中删除。
自定义事件监听:UI控件继承UIBehaviour基类,因此,传入控件类型,控件响应类型,响应函数即可。
public enum E_UI_Layer
{
Top,
Bot,
Mid,
System,
}
public class UIManager : BaseManager<UIManager>
{
//字典容器
Dictionary<string,BasePanel> panelDic = new Dictionary<string,BasePanel>();
//各层
private Transform top;
private Transform bot;
private Transform mid;
private Transform system;
//初始化
public UIManager()
{
//加载Canvas 过场景不移除
GameObject canvas = ResManager.Instance.Load<GameObject>("UI/Canvas");
GameObject.DontDestroyOnLoad(canvas);
//加载EventSystem
GameObject eventSystem = ResManager.Instance.Load<GameObject>("UI/EventSystem");
GameObject.DontDestroyOnLoad(canvas);
//找到各层
top = canvas.transform.Find("Top");
bot = canvas.transform.Find("Bot");
mid = canvas.transform.Find("Mid");
system = canvas.transform.Find("System");
}
//显示面板
public void ShowPanel<T>(string panelName , E_UI_Layer layer = E_UI_Layer.Mid , UnityAction<T> callBack = null) where T : BasePanel
{
if(panelDic.ContainsKey(panelName))
{
panelDic[panelName].ShowMe();
if(callBack != null)
{
callBack(panelDic[panelName] as T);
}
return;
}
//加载面板
ResManager.Instance.LoadAsync<GameObject>(panelName, (obj) =>
{
//得到panel挂载的脚本
T panel = obj.GetComponent<T>();
if(callBack != null)
callBack(panel);
Transform father = mid;
switch (layer)
{
case E_UI_Layer.Bot:
father = bot;
break;
case E_UI_Layer.System:
father = system;
break;
case E_UI_Layer.Top:
father = top;
break;
}
obj.transform.SetParent(father, false);
//显示面板
panel.ShowMe();
//存起来
panelDic.Add(panelName, panel);
});
}
//隐藏面板
public void HidePanel(string panelName)
{
if (panelDic.ContainsKey(panelName))
{
//隐藏自己要执行的逻辑
panelDic[panelName].HideMe();
GameObject.Destroy(panelDic[panelName].gameObject);
//字典中移除
panelDic.Remove(panelName);
}
}
//得到层级
public Transform GetLayerFather(E_UI_Layer layer)
{
switch (layer)
{
case E_UI_Layer.Bot:
return this.bot;
case E_UI_Layer.Mid:
return this.mid;
case E_UI_Layer.Top:
return this.top;
case E_UI_Layer.System:
return this.system;
}
return null;
}
public static void AddCustomEventListener(UIBehaviour control, EventTriggerType type , UnityAction<BaseEventData> callback)
{
//自定义事件监听控件
EventTrigger trigger = control.GetComponent<EventTrigger>();
if (trigger == null) {
trigger = control.gameObject.AddComponent<EventTrigger>();
}
EventTrigger.Entry entry = new EventTrigger.Entry();
//事件类型
entry.eventID = type;
//响应函数
entry.callback.AddListener(callback);
//加入控件中
trigger.triggers.Add(entry);
}
}
面板基类
作用:为了不用每次都去关联UI控件,这里直接实现找到所有UI控件脚本,并用字典存储。
字典:UI控件名为Key,链表为Value(存储该UI控件下所有UI控件脚本)
两个主要函数:FindChildrenControl,用于找到该面板下所有UI控件挂载的脚本。
GetControl,得到该面板指定UI控件对应的UI控件脚本。
public class BasePanel : MonoBehaviour
{
// Start is called before the first frame update
Dictionary<string, List<UIBehaviour>> controlDic = new Dictionary<string, List<UIBehaviour>>();
protected virtual void Awake()
{
FindChildrenControl<Button>();
FindChildrenControl<Image>();
FindChildrenControl<Text>();
FindChildrenControl<Toggle>();
FindChildrenControl<Slider>();
FindChildrenControl<ScrollRect>();
FindChildrenControl<InputField>();
}
public virtual void ShowMe()
{
}
public virtual void HideMe() { }
protected virtual void OnClick(string btnName)
{
}
protected virtual void OnValueChange(string toggleName , bool value)
{
}
protected virtual T GetControl<T>(string controlName) where T : UIBehaviour
{
if(controlDic.ContainsKey(controlName))
{
for(int i = 0; i < controlDic[controlName].Count; i++)
{
if (controlDic[controlName][i] is T)
{
return controlDic[controlName][i] as T;
}
}
}
return null;
}
private void FindChildrenControl<T>() where T : UIBehaviour
{
T[] controls = gameObject.GetComponentsInChildren<T>();
for(int i = 0; i < controls.Length; i++)
{
string controlName = controls[i].gameObject.name;
if(controlDic.ContainsKey(controlName))
{
controlDic[controlName].Add(controls[i]);
}
else
{
controlDic.Add(controlName, new List<UIBehaviour>() { controls[i] });
}
}
}
}
使用:在某一面板类中如下调用即可
private void Start()
{
GetControl<Button>("btnSetting").onClick.AddListener(() =>
{
print("被点击");
});
UIManager.AddCustomEventListener(GetControl<Button>("btnSetting"), EventTriggerType.PointerEnter, (data) =>
{
print("鼠标进入" + (data as PointerEventData).position);
});
}