Unity 二级弹窗机制与回调实现原理
一、什么是二级弹窗?
二级弹窗指在一个弹窗上再弹出另一个弹窗,且需要将用户操作结果回传给调用方。
示例场景:
- 主界面(GamePlayerInfo)→ 点击踢出按钮 → 弹出确认弹窗(ConfirmPopup)
- 用户点击确认/取消后,主界面需要根据结果执行操作(如销毁玩家项)
二、为什么需要回调机制?
普通弹窗:打开后关闭,调用方不需要知道结果。
二级弹窗:需要知道用户的选择,并根据结果执行后续操作。
问题:弹窗如何将结果传递给调用方?
解决方案:回调机制(Callback Pattern)
三、核心设计:回调接口
// 定义回调接口
public interface IUIResultCallback
{void OnUIResult(string result);
}
设计要点:
- 接口定义统一的结果接收方法
- 使用字符串传递结果(可扩展为枚举或对象)
- 调用方实现该接口,接收结果
四、UIManager:回调的中转站
UIManager 作为回调的中间层,负责:
- 保存回调对象
- 接收弹窗的结果
- 将结果传递给回调对象
public class UIManager : MonoBehaviour
{// 保存当前的回调对象private IUIResultCallback callback;// 打开带回调的UIpublic async ETTask<GameObject> ShowUIWithCallback(IUIResultCallback cb, // 回调对象string uiName, // UI名称string tag, // UI层级UIOpenActionType iType, // 打开动画类型params object[] p // 初始化参数){callback = cb; // 保存回调对象// 打开UI...Transform node = tag == "pop" ? PopLayer.transform : ...;GameObject Logic = await OpenUI(node, uiName, iType, p);return Logic;}// 发送结果给回调对象public void SendResult(string result){if (callback != null){callback.OnUIResult(result); // 调用回调方法}}
}
为什么需要 UIManager 中转?
- 解耦:弹窗不需要知道调用方是谁
- 统一管理:集中处理回调逻辑
- 单例模式:全局可访问
五、弹窗:发送结果
弹窗(ConfirmLogic)在用户操作时,通过 UIManager 发送结果:
public class ConfirmLogic : MonoBehaviour, IGameUI
{public void Awake(){BtnSure.onClick.AddListener(() =>{UIManager.instance.SendResult("1"); // 发送确认结果Close();});BtnCancel.onClick.AddListener(() =>{UIManager.instance.SendResult("0"); // 发送取消结果Close();});}
}
要点:
- 弹窗不直接调用调用方
- 通过 UIManager 统一发送
- 使用字符串标识结果(“1”=确认,“0”=取消)
六、调用方:实现回调接口
调用方(GamePlayerInfo)实现 IUIResultCallback,接收结果:
public class GamePlayerInfo : ScrollItem, IUIResultCallback
{public void Awake(){kickBtn.onClick.AddListener(async () =>{// 打开弹窗,传入自身作为回调对象await UIManager.instance.ShowUIWithCallback(this, // 传入自身作为回调"ConfirmPopup", "pop", UIOpenActionType.CenterSmallToBig,"确定要踢出该玩家吗?");});}// 实现回调接口,接收弹窗结果public void OnUIResult(string result){if (result == "1") // 用户点击了确认{// 执行后续操作:发送网络请求、销毁对象等C2S_PlayerLeave msg = C2S_PlayerLeave.Create();msg.Uids.Add(playerUid);GameApp.Send(msg);Destroy(gameObject);}// result == "0" 表示取消,不需要处理}
}
要点:
- 实现
IUIResultCallback - 打开弹窗时传入
this作为回调 - 在
OnUIResult中处理结果
七、完整工作流程
┌─────────────────────────────────────────────────────────┐
│ 1. 用户点击 kickBtn │
└─────────────────────────────────────────────────────────┘↓
┌─────────────────────────────────────────────────────────┐
│ 2. GamePlayerInfo 调用 │
│ UIManager.ShowUIWithCallback(this, "ConfirmPopup") │
└─────────────────────────────────────────────────────────┘↓
┌─────────────────────────────────────────────────────────┐
│ 3. UIManager 保存 callback = this │
│ 然后打开 ConfirmPopup 弹窗 │
└─────────────────────────────────────────────────────────┘↓
┌─────────────────────────────────────────────────────────┐
│ 4. 用户点击确认/取消按钮 │
└─────────────────────────────────────────────────────────┘↓
┌─────────────────────────────────────────────────────────┐
│ 5. ConfirmLogic 调用 │
│ UIManager.SendResult("1" 或 "0") │
└─────────────────────────────────────────────────────────┘↓
┌─────────────────────────────────────────────────────────┐
│ 6. UIManager 调用 │
│ callback.OnUIResult("1") │
└─────────────────────────────────────────────────────────┘↓
┌─────────────────────────────────────────────────────────┐
│ 7. GamePlayerInfo.OnUIResult("1") 被调用 │
│ 执行后续操作(发送请求、销毁对象等) │
└─────────────────────────────────────────────────────────┘
八、设计模式:回调模式(Callback Pattern)
这是回调模式的典型应用:
- 定义接口:
IUIResultCallback - 调用方实现接口:
GamePlayerInfo : IUIResultCallback - 传递回调对象:
ShowUIWithCallback(this, ...) - 异步执行:弹窗操作是异步的
- 结果回调:通过
OnUIResult返回结果
优点:
- 解耦:弹窗与调用方解耦
- 灵活:任何实现接口的类都可以作为回调
- 可扩展:可以传递多个参数或复杂对象
九、关键要点总结
- 接口定义:统一的结果接收接口
- 中转管理:UIManager 作为回调的中转站
- 结果传递:弹窗通过 UIManager 发送结果
- 回调实现:调用方实现接口并处理结果
- 解耦设计:弹窗不需要知道调用方是谁
十、适用场景
需要回调机制:
- 确认对话框(需要知道用户选择)
- 输入对话框(需要获取用户输入)
- 选择对话框(需要知道用户选择)
不需要回调机制:
- 信息展示弹窗(只是查看,无需反馈)
- 提示弹窗(只是提示,无需操作)
- 独立功能弹窗(不依赖调用方状态)
这个机制的核心思想是:通过接口定义契约,通过 UIManager 中转回调,实现弹窗与调用方的解耦,让弹窗可以灵活地通知调用方用户的操作结果。
