UE5 Common UI Button Development
Common UI is the standard UE5 UI framework (used by Fortnite, Lyra). Always prefer Common UI over plain UMG UButton for new button development.
Critical: UButton vs UCommonButtonBase API Incompatibility
UButton::OnClicked and UCommonButtonBase click handling are NOT compatible.
| Feature | UButton | UCommonButtonBase |
|---|---|---|
| Click delegate | FOnButtonClickedEvent OnClicked (no params) | NOT available as public delegate |
| C++ click binding | Btn->OnClicked.AddDynamic(this, &Handler) | NOT possible — use NativeOnClicked() override |
| Blueprint click | OnClicked event node | BP_OnClicked (BlueprintImplementableEvent) |
| Type | UWidget subclass | UUserWidget subclass |
| SetVisibility() | ✅ Direct | ✅ Inherited from UWidget |
| GetCachedGeometry() | ✅ Direct | ✅ Inherited from UWidget |
Migration from UButton to UCommonButtonBase requires PER-CLASS rewrite of click handling. Simple search-and-replace of type declarations will fail because:
OnClickeddelegate doesn't exist onUCommonButtonBaseTObjectPtr<T>needs full type definition —.cppfiles must#includethe header, not just forward-declare
Migration path if needed:
- Option A: Override
NativeOnClicked()in each widget class - Option B: Move click logic to Blueprint
BP_OnClickedevents - Option C (simplest): Keep C++ code using
UButton, only useUXxxButtonBasefor NEW buttons
Quick Decision: Common UI vs Plain UMG
| Requirement | Plain UMG UButton | Common UI |
|---|---|---|
| Per-instance style config | ✅ Style panel | ❌ No built-in style panel |
| Centralized style (one asset, many buttons) | ❌ Need custom DataAsset | ✅ UCommonButtonStyle |
| Hover image swap | ✅ FButtonStyle states | ✅ 7-state style brush |
| Selected/toggleable state | ❌ Manual | ✅ Built-in SetIsSelected |
| Gamepad focus navigation | ❌ Manual | ✅ Built-in input routing |
| Controller button hints | ❌ None | ✅ CommonActionWidget |
| Text style per button state | ❌ Manual | ✅ 5 text styles in style asset |
| Cross-platform controller icons | ❌ None | ✅ Platform data tables |
Project Setup Checklist
1. Edit → Plugins → Enable "Common UI" (may require restart)
2. Project Settings → Engine → General Settings
→ Game Viewport Client Class = CommonGameViewportClient
3. Project Settings → Game → Common Input Settings
→ Create CommonUIInputData Blueprint → Input Data = your asset
4. Build.cs add: "CommonUI", "CommonInput" to module dependencies
New Module Registration (CRITICAL)
UE5 模块必须在 3 个位置注册,缺一不可:
.uproject的Modules数组- 所有 4 个 Target.cs 的
ExtraModuleNames(Editor/Game/Client/Server) Source/<ModuleName>/<ModuleName>.Build.cs
Core Architecture
UCommonButtonStyle (Data Asset)
├─ 7 Brush states (Normal/Hovered/Pressed × Selected/Unselected + Disabled)
├─ 5 Text styles (per state)
├─ Sound overrides
└─ Min width/height, padding
UCommonButtonBase (Abstract UserWidget)
├─ Internal: UCommonButtonInternalBase
├─ BindWidget: UCommonTextBlock → text follows state
├─ BP Events: OnClicked, OnHovered, OnSelected, OnDoubleClicked, ...
└─ Optional: CommonActionWidget
BP_GenericButton (Your reusable base)
├─ Layout: Overlay + CommonTextBlock named "ButtonText"
└─ Style: assigned in Class Defaults
Creating a Generic Reusable Button
C++ Base Class (Handles Text Style Auto-Swap)
Key pitfall: UCommonButtonBase auto-swaps brush images but does NOT auto-swap text styles. You MUST override NativeOnCurrentTextStyleChanged().
UCLASS(Blueprintable, meta = (DisableNativeTick))
class UXxxButtonBase : public UCommonButtonBase
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable)
void SetButtonText(const FText& InText);
protected:
virtual void NativeOnCurrentTextStyleChanged() override;
virtual void NativePreConstruct() override;
UPROPERTY(meta = (BindWidget))
TObjectPtr<UCommonTextBlock> ButtonText;
UPROPERTY(EditInstanceOnly, BlueprintReadWrite)
FText ButtonLabel;
};
void UXxxButtonBase::NativeOnCurrentTextStyleChanged()
{
Super::NativeOnCurrentTextStyleChanged();
if (ButtonText) ButtonText->SetStyle(GetCurrentTextStyleClass());
}
void UXxxButtonBase::NativePreConstruct()
{
if (GetWorld()) Super::NativePreConstruct(); // guard against editor context
if (ButtonText && !ButtonLabel.IsEmpty()) ButtonText->SetText(ButtonLabel);
}
Blueprint Widget
- Widget Blueprint → Parent =
UXxxButtonBase→WBP_GenericButton - Designer: Overlay + CommonTextBlock named exactly "ButtonText"
- Class Defaults → Style = your
UCommonButtonStyleasset - Details → ButtonLabel = default text
Variants: Right-click WBP_GenericButton → Create Child Widget Blueprint → only change Style.
UCommonButtonStyle Configuration
7 Brush states: NormalBase, NormalHovered, NormalPressed, SelectedBase, SelectedHovered, SelectedPressed, Disabled. 5 Text styles: NormalTextStyle, NormalHoveredTextStyle, SelectedTextStyle, SelectedHoveredTextStyle, DisabledTextStyle.
Common Pitfalls
| Symptom | Cause | Fix |
|---|---|---|
| Text doesn't change style on hover | NativeOnCurrentTextStyleChanged not overriding | Add override, call ButtonText->SetStyle() |
| CommonButtonBase can't be placed | It's Abstract | Create Blueprint subclass first |
| Module not compiled | Missing from Target.cs ExtraModuleNames | Add to ALL 4 target files |
| Build says "Target is up to date" | Build.cs missing from Source/ | Verify file exists and committed |
| OnClicked compile error | UCommonButtonBase has no public OnClicked delegate | Use NativeOnClicked() override or BP_OnClicked |
微信扫一扫