总览
游戏 UI 里最容易乱的是弹窗:确认框、奖励、网络错误、购买提示、加载遮罩、好友邀请都想盖在最上面。Common UI 给你的工具是:Modal 页面、Modal Stack、Queue、LoadGuard 和 Lazy Widget/Image。
Modal 页面怎么定义
UCommonActivatableWidget 有 bIsModal。Modal 的语义是:它在前台时,下面的页面不应该继续接收输入。确认框、购买弹窗、删除存档都应该是 Modal。
确认框建议:
- 继承
CommonActivatableWidget bIsBackHandler=truebIsModal=true- Desired Focus 返回“取消”按钮,而不是危险的“确认”按钮
- Confirm 和 Cancel 都 Deactivate 自己,并把结果回调给打开者
Modal Stack 不要和 Menu Stack 混用
把确认框 Push 到 Layer_Modal,不要 Push 到 Layer_Menu。这样设置页仍然在下面,但输入被 Modal 抢走;确认框关闭后,设置页的焦点和输入配置能恢复。
UConfirmDialog* Dialog = LayerModal->AddWidget<UConfirmDialog>(
ConfirmDialogClass,
[Message, OnResult](UConfirmDialog& Widget)
{
Widget.Setup(Message, OnResult);
});
CommonLoadGuard
UCommonLoadGuard 像一个会显示加载状态的 Border。它可以 SetIsLoading(true),也可以 GuardAndLoadAsset,等软引用资源加载完成后再显示内容。
适合:
- 商店物品大图异步加载。
- 角色预览 Widget 异步创建。
- 网络请求未返回时锁住局部面板。
- 大地图缩略图未加载时显示 spinner。
LoadGuard->SetLoadingText(NSLOCTEXT("UI", "Loading", "加载中"));
LoadGuard->SetIsLoading(true);
RequestInventoryAsync([this](const FInventoryData& Data)
{
RefreshInventory(Data);
LoadGuard->SetIsLoading(false);
});
页面 Deactivate 时要取消请求或忽略回调,避免异步返回后刷新已关闭页面。
CommonLazyImage 和 CommonLazyWidget
LazyImage 适合软引用图片,LazyWidget 适合软引用 Widget Class。项目中商店、图鉴、任务详情经常要用它们。不要在打开页面的一瞬间同步加载大量图标,否则菜单卡顿会很明显。
Queue 处理非阻塞提示
奖励 Toast、成就提示、保存成功提示适合 CommonActivatableWidgetQueue。当前 Toast 播放动画后 Deactivate,Queue 自动显示下一个。不要把这些提示做成 Modal,玩家会烦。
使用案例:删除存档
流程:
- 玩家长按删除按钮。
- 打开 Modal 确认框。
- 默认焦点在“取消”。
- Confirm 后确认框进入 Loading 状态,禁用按钮。
- 异步删除完成,确认框 Deactivate。
- Toast Queue 显示“存档已删除”。
这个流程里每一步都在自己的层:列表页在 Menu,确认框在 Modal,成功提示在 Toast。
常见坑
- 确认框放 Menu Stack,Back 后返回路径错乱。
- Modal 没设置 Desired Focus,手柄打开后无法选择按钮。
- 异步回调里直接访问已 Deactivate 的页面。
- Loading 遮罩只是视觉层,没有阻止底下按钮点击。
- Toast 用 Modal,导致每个奖励提示都挡玩家输入。
源码依据
UCommonLoadGuard 注释说明它类似 Border,但能在内容加载或准备期间隐藏主内容、显示 spinner 和可选文本,并支持 GuardAndLoadAsset。UCommonActivatableWidget 提供 bIsModal、Desired Input Config、Back Handler 和 Activation 生命周期。UCommonActivatableWidgetQueue 适合一次显示一个 widget,当前停用后再显示下一个。
源码路径索引
CommonUI/Public/CommonActivatableWidget.hCommonUI/Public/CommonLoadGuard.hCommonUI/Public/CommonLazyImage.hCommonUI/Public/CommonLazyWidget.hCommonUI/Public/Widgets/CommonActivatableWidgetContainer.h