框架
所谓框架就是搭建好一个架子,拆箱即用,直接上手,像使用工具一样十分方便
0. 资源链接
UI框架学习 手搓UI框架(TransformHelper,UIEventListener,UIWindow,UIMgr)
1. TransformHelper
using UnityEngine;
namespace FrameWorkStudy.Utils
{
/// <summary>
/// 变换组件(Transform)工具类
/// </summary>
public static class TransformHelper
{
/// <summary>
/// 通过子节点名字递归查找节点
/// </summary>
/// <param name="parentRoot">this修饰, 作为Transform扩展方法</param>
/// parentRoot.FindChildByName(childName) <=> TransformHelper.FindChildByName(parentRoot, childName)
/// <param name="childName">节点名称</param>
/// <returns></returns>
public static Transform FindChildByName(this Transform parentRoot, string childName)
{
var tf = parentRoot.Find(childName);
if (tf != null) return tf;
for (int i = 0; i < parentRoot.childCount; i++)
{
tf = FindChildByName(parentRoot.GetChild(i), childName);
if (tf != null) return tf;
}
return null;
}
// 以后如果有其他工具函数也写在这里,例如旋转,缩放...
}
}
2. UIEventListener
using System;
using UnityEngine;
using UnityEngine.EventSystems;
namespace FrameWorkStudy.Event
{
/// <summary>
/// UI事件监听类
/// </summary>
public class UIEventListener : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerClickHandler // 可以继续实现接口IDragHandler,需要什么事件就实现什么接口
{
public event Action<PointerEventData> OnClickAction; // 点击
public event Action<PointerEventData> OnUpAction; // 抬起
public event Action<PointerEventData> OnDownAction; // 按下
public static UIEventListener GetEventListener(Transform tf)
{
var uiEvent = tf.GetComponent<UIEventListener>();
if (uiEvent == null)
{
uiEvent = tf.gameObject.AddComponent<UIEventListener>();
}
return uiEvent;
}
public void OnPointerClick(PointerEventData eventData)
{
OnClickAction?.Invoke(eventData);
}
public void OnPointerDown(PointerEventData eventData)
{
OnDownAction?.Invoke(eventData);
}
public void OnPointerUp(PointerEventData eventData)
{
OnUpAction?.Invoke(eventData);
}
}
}
UIEventListener可以仿造EventTrigger写,EventTrigger所包含的事件是比较全的
public class EventTrigger : MonoBehaviour,
IPointerEnterHandler, IPointerExitHandler,
IPointerDownHandler, IPointerUpHandler, IPointerClickHandler,
IInitializePotentialDragHandler,
IBeginDragHandler, IDragHandler, IEndDragHandler,
IDropHandler,
IScrollHandler,
IUpdateSelectedHandler, ISelectHandler, IDeselectHandler,
IMoveHandler,
ISubmitHandler, ICancelHandler
{
// ...
}
但是通过在面板中点击AddComponent添加EventTrigger发现,这是要手动拖函数实现**(例如点击)**事件回调,而我们实际项目中事件绑定都需要通过代码来写,这样便于管理(+=,-=),所以这里不使用EventTrigger这种办法,而是自定义事件监听类UIEventListener
3. UIWindow
using FrameWorkStudy.Event;
using FrameWorkStudy.Utils;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace FrameWorkStudy.UI
{
public class UIWindow : MonoBehaviour
{
private CanvasGroup canvasGroup;
/// <summary>
/// 对同一节点缓存UI事件
/// </summary>
private Dictionary<string, UIEventListener> evtListenerDics = new Dictionary<string, UIEventListener>();
private void Awake()
{
canvasGroup = GetComponent<CanvasGroup>();
}
public void SetVisible(bool state, int delay = 0)
{
StartCoroutine(SetVisibleDelay(state, delay));
}
public IEnumerator SetVisibleDelay(bool state, int delay)
{
yield return new WaitForSeconds(delay);
// Unity官方不建议使用SetActive(false)隐藏, 建议通过修改canvasGroup的alpha值来显隐UI
// 当然,如果您的项目没有这个要求,使用SetActive(...)来显隐UI也无伤大雅
canvasGroup.alpha = state ? 1 : 0;
}
public UIEventListener GetUIEventListener(string childName)
{
if (!evtListenerDics.ContainsKey(childName))
{
var tf = transform.FindChildByName(childName);
var uiEvent = UIEventListener.GetEventListener(tf);
evtListenerDics.Add(childName, uiEvent);
}
return evtListenerDics[childName];
}
}
}
4. UIMgr
MonoSingleton是一个单例脚本,详情见上一小记【C#】Unity单例脚本
using FrameWorkStudy.MonoSingleton;
using FrameWorkStudy.UI;
using System.Collections.Generic;
using UnityEditor.PackageManager.UI;
namespace FrameWorkStudy.Mgr
{
public class UIMgr : MonoSingleton<UIMgr>
{
private Dictionary<string, UIWindow> uiWindowDics;
public override void Init()
{
base.Init();
uiWindowDics = new Dictionary<string, UIWindow>();
var uiWindows = FindObjectsOfType<UIWindow>();
foreach (var uiWindow in uiWindows)
{
uiWindow.SetVisible(false);
AddUIWindow(uiWindow);
}
}
public void AddUIWindow(UIWindow window)
{
uiWindowDics.Add(window.GetType().Name, window);
}
public UIWindow GetWindow<T>()
{
string key = typeof(T).Name;
return uiWindowDics.ContainsKey(key) ? uiWindowDics[key] : null;
}
}
}