UE5.8 Common UI 喂饭级专题

UE5.8 Common UI 专题(二):Activatable Widget 生命周期

讲清 UCommonActivatableWidget 的 Construct、Activate、Deactivate、Destruct、Back Handler、Desired Focus、Input Config、Action Domain、Mapping Context 和焦点恢复。

总览

UCommonActivatableWidget 是 Common UI 的核心。它不是 UUserWidget 的替代品,而是给“页面”加了一套激活协议。普通 UMG 的 Construct/Destruct 只告诉你 Widget 被创建和销毁;游戏菜单更需要的是“页面现在是否在前台、是否接收输入、是否该恢复焦点、是否该把鼠标/手柄输入模式切到 UI”。

UE5.8 Common UI 专题(二):Activatable Widget 生命周期 配图
Activatable Widget 的重点是激活/停用,不是反复创建/销毁;它是输入树里的页面节点。

生命周期顺序

NativeConstruct
  -> 如果 bIsBackHandler,注册默认 Back Action
  -> 如果 bAutoActivate,ActivateWidget

ActivateWidget
  -> NativeOnActivated
  -> 可选 SetVisibility
  -> ActivateMappingContext
  -> BP_OnActivated / OnActivated

DeactivateWidget
  -> NativeOnDeactivated
  -> 可选 SetVisibility
  -> DeactivateMappingContext
  -> ClearActiveHoldInputs
  -> BP_OnDeactivated / OnDeactivated

NativeDestruct
  -> DeactivateWidget
  -> Unregister Back Action

关键点:Deactivate 不是 Destroy。 一个页面可以被池化、重新激活、重新放回栈里。所以每次激活都要刷新显示数据,每次停用都要清理定时器、异步请求、长按输入和临时状态。

Back Handler 怎么用

页面如果勾选 bIsBackHandlerNativeConstruct 会注册默认 Back Action。默认行为是调用 DeactivateWidget()。你可以在 BP_OnHandleBackActionNativeOnHandleBackAction 里拦截:

bool UMySettingsScreen::NativeOnHandleBackAction()
{
    if (bHasUnsavedChanges)
    {
        OpenConfirmDiscardDialog();
        return true;
    }

    return Super::NativeOnHandleBackAction();
}

如果返回 true 表示你处理了;如果需要默认关闭,就让父类处理或自己 Deactivate。

Desired Focus 必须认真写

Common UI 会在 leaf-most active widget 变化时尝试给它焦点。NativeGetDesiredFocusTarget 先调用蓝图 BP_GetDesiredFocusTarget,没有的话回退到 UUserWidget 的 DesiredFocusWidget 属性。

生产项目建议每个页面都明确返回:

  • 主菜单:默认选中的主按钮。
  • 设置页:当前 Tab 或第一个设置项。
  • 确认框:默认安全按钮,例如“取消”。
  • 背包详情页:如果从列表进来,返回详情页的操作按钮;回列表时恢复上一项。

Input Config 是页面说“我要哪种输入模式”

GetDesiredInputConfig 返回可选 FUIInputConfig。常见三种:

页面InputModeMouseCapture
主菜单/设置MenuNoCapture
HUD 上的交互轮盘AllNoCapture
游戏内瞄准预览菜单AllCapturePermanently

蓝图里实现 BP_GetDesiredInputConfig 即可。源码里如果整棵激活树都没有 Desired Config,并且 bEnableDefaultInputConfig 为 true,会回退到默认 Menu config。

Enhanced Input Mapping Context

UCommonActivatableWidgetInputMappingInputMappingPriority。当 Common UI Enhanced Input Support 开启时,页面激活会把这个 IMC 加到 UEnhancedInputLocalPlayerSubsystem,停用时移除。适合页面专属输入,例如设置页的左右切换、相册页的缩放、地图页的拖拽。

不要把全游戏默认移动 IMC 放到页面上;页面上的 InputMapping 应该是 UI 专属、短生命周期。

Action Domain 简单理解

Action Domain 用来控制多个 UI 域之间输入如何流动。比如你有 HUD 域、菜单域、调试覆盖层域,某个域 active 时是否阻断其他域,由 UCommonInputActionDomainBehaviorInnerBehavior 决定。新手可以先不建复杂 Domain,但要知道 bOverrideActionDomain 是页面级覆盖点。

常见坑

  • NativeConstruct 里读存档并只初始化一次,页面从池里回来后显示旧数据。
  • NativeOnDeactivated 忘记清定时器,页面关闭后还在 Tick/回调。
  • Back Handler 页面里打开确认框时先 Deactivate 自己,导致确认框下面页面没了。
  • Desired Focus 返回隐藏或 Disabled 的按钮,焦点会失败。
  • 页面 InputMapping 里绑定了和 gameplay 一样的攻击键,却没有明确 InputMode/优先级。

源码依据

CommonActivatableWidget.cppNativeConstruct 会注册 Back Action,NativeOnActivated 会设置可选可见性并调用 ActivateMappingContextNativeOnDeactivated 会移除 Mapping Context 并 ClearActiveHoldInputsNativeGetDesiredFocusTarget 会优先取 BP 实现,再取 UserWidget 的 Desired Focus。FActivatableTreeRoot::ApplyLeafmostNodeConfig 会把 leaf-most node 的 Desired Input Config 应用到 Action Router。

源码路径索引

  • CommonUI/Public/CommonActivatableWidget.h
  • CommonUI/Private/CommonActivatableWidget.cpp
  • CommonUI/Private/Input/UIActionRouterTypes.cpp
  • CommonInput/Public/CommonInputActionDomain.h