在上一节中,我们完成了按钮事件的自动转发------ButtonCustom
会自动向上查找并调用页面的 PanelBase.ProcessEvent()
,从而完成"业务逻辑接收"。
但实际项目里我们当然不会只用到 Button,对吧?
Toggle、Slider、InputField、Dropdown......它们都是交互控件,也需要转发事件。
所以本节我们要解决一个关键问题:
❓ 怎么让所有 UI 控件都能使用统一的事件系统,而不是每个都写一套重复逻辑?
🎯 通用方案:抽取公共基类 EventUIBase
所有 UI 控件的事件脚本,其实逻辑大同小异:
-
初始化时找到上级页面(PanelBase)
-
在事件触发时转发自己给 PanelBase
因此,我们可以将"向上查找 PanelBase"这段逻辑提取出来,放进一个共同基类 EventUIBase
中。
cs
using UnityEngine;
public class EventUIBase : MonoBehaviour
{
protected PanelBase targetPanel;
protected virtual void Init()
{
Transform current = transform;
while (current != null)
{
targetPanel = current.GetComponent<PanelBase>();
if (targetPanel != null)
return;
current = current.parent;
}
Debug.LogWarning("No parent with PanelBase found.");
}
}
✅ 示例:扩展 Button 与 Toggle 的事件脚本
现在我们基于 EventUIBase
,轻松地扩展任意控件,只需专注于各自的事件监听绑定即可:
cs
using UnityEngine.UI;
public class ButtonCustom : EventUIBase
{
private Button btn;
protected override void Init()
{
base.Init();
btn = GetComponent<Button>();
btn.onClick.AddListener(() =>
{
targetPanel.ProcessEvent(this);
Debug.Log($"{name} 触发点击事件");
});
}
}
cs
using UnityEngine.UI;
public class ToggleCustom : EventUIBase
{
private Toggle tog;
protected override void Init()
{
base.Init();
tog = GetComponent<Toggle>();
tog.onValueChanged.AddListener((bool newValue) =>
{
targetPanel.ProcessEvent(this);
Debug.Log($"{name} 触发值变更事件");
});
}
}
其他控件(如Slider、Dropdown、InputField)也可仿照上述写法扩展,你只需监听它们自身的变更事件并转发即可。
🧠 面板逻辑:统一处理所有 UI 控件事件
观察上面的代码,你可能会问:
"
PanelBase.ProcessEvent()
不是只能接收ButtonCustom
吗?那 ToggleCustom 怎么进来的?"
这是我们接下来要修改的地方:我们要将 ProcessEvent
改写为泛型方法 ,并且限制只接受继承自 EventUIBase
的对象。
这样就能让所有 UI 控件统一走这套通道:
cs
public class PanelBase : MonoBehaviour
{
public void ProcessEvent<T>(T eventUI) where T : EventUIBase
{
switch (eventUI.name)
{
case "开始游戏":
Debug.Log("开始游戏");
break;
case "退出游戏":
Debug.Log("退出游戏");
break;
default:
Debug.LogWarning($"未处理的控件事件:{eventUI.name}");
break;
}
}
}
🧩 新问题浮现:脚本挂载仍需手动完成?
虽然现在我们解决了多个控件统一事件处理的问题,但你可能已经意识到:
"我们还是得自己一个个给控件挂上
ButtonCustom
、ToggleCustom
,这不还是重复劳动吗?"
没错,这仍然不够自动化,而且一不小心挂错脚本还会导致事件丢失或报错。
所以下一节我们将进入编辑器扩展的世界,写一套"一键挂载 UI 基础脚本"的工具,彻底解放你的右手!
不过提前说一句,下一节不会解决所有控件扩展的逻辑,只是处理自动挂载与类型匹配,核心问题我们将逐步展开。