UI框架从0到1第二节:【全控件适配】把 Toggle、InputField 全都拉进事件系统

在上一节中,我们完成了按钮事件的自动转发------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;
		}
	}
}

🧩 新问题浮现:脚本挂载仍需手动完成?

虽然现在我们解决了多个控件统一事件处理的问题,但你可能已经意识到:

"我们还是得自己一个个给控件挂上 ButtonCustomToggleCustom,这不还是重复劳动吗?"

没错,这仍然不够自动化,而且一不小心挂错脚本还会导致事件丢失或报错。

所以下一节我们将进入编辑器扩展的世界,写一套"一键挂载 UI 基础脚本"的工具,彻底解放你的右手!

不过提前说一句,下一节不会解决所有控件扩展的逻辑,只是处理自动挂载与类型匹配,核心问题我们将逐步展开。

相关推荐
kirayoshikake1 天前
UGUI 性能优化系列:第二篇——Canvas 与 UI 元素管理
unity3d
kirayoshikake1 天前
UI框架从0到1第九节:【脚本模板生成】怎么用代码生成代码?
unity3d
kirayoshikake1 天前
Unity入门教程之异步篇第五节:对UniTask的高级封装
unity3d
kirayoshikake1 天前
UI框架从0到1第六节:【轻量 MVVM】用属性驱动 UI,彻底抛弃命令式调用
unity3d
kirayoshikake1 天前
Unity入门教程之异步篇第一节:协程基础扫盲--非 Mono 类如何也能启动协程?
unity3d
kirayoshikake1 天前
响应式编程入门教程第一节:揭秘 UniRx 核心 - ReactiveProperty - 让你的数据动起来!
unity3d
kirayoshikake1 天前
UI框架从0到1第五节:【事件消息体】不仅知道你点了啥,还知道你改了啥
unity3d
kirayoshikake1 天前
响应式编程入门教程第六节:进阶?Combine、Merge、SelectMany 与错误处理
unity3d
kirayoshikake1 天前
对象池由浅入深第三节:基于 ObjectPoolPro 扩展 Unity 对象池--泛型对象池、自动回收和场景隔离
unity3d