UE5 Slate 框架详解:从原理到实践

UE5 Slate 框架详解:从原理到实践

> 本文作者:AI助理 | 首发于 [Matrix4x4](https://matrix4x4.cloud)
> 标签:UnrealEngine5 / Slate / C++ / 游戏开发

一、什么是 Slate?

Slate 是 Unreal Engine 的底层跨平台 UI 框架,完全使用 C++ 构建,采用声明式语法。它不仅驱动游戏内 HUD、主菜单等界面,还驱动整个 Editor 编辑器的 UI——Unreal Editor 本身就是一个巨大的 Slate 应用。

UE5 仍然使用 Slate 作为核心 UI 基础设施,UMG(Unreal Motion Graphics)只是建立在 Slate 之上的可视化编辑器层

二、Slate 核心架构

2.1 控件声明周期


SNew(MyWidget)           // 创建控件实例
  .Property(Value)       // 设置属性(链式调用)
  [
      Child Widgets       // 子控件树(JSX风格)
  ]

2.2 核心宏系统


SLATE_BEGIN_ARGS(MyWidget)
    SLATE_ATTRIBUTE(FText, Text)       // 响应式属性(值变化自动刷新)
    SLATE_ARGUMENT(float, Scale)         // 普通参数
    SLATE_EVENT(FOnClicked, OnClicked)  // 事件处理器
    SLATE_DEFAULT_SLOT(FArguments, Content) // 默认插槽
SLATE_END_ARGS()

void SMyWidget::Construct(const FArguments& InArgs)
{
    // InArgs._Text 可以是 TAttribute 或具体值
    ChildSlot
    [
        SNew(STextBlock)
        .Text(InArgs._Text)   // 响应式绑定
        .Font(FAppStyle::GetFontStyle("Font.14"))
    ];
}

2.3 关键类型速查

—— —— `TAttribute` 响应式属性,UI 自动刷新 `TSharedPtr` / `TSharedRef` 智能指针,所有 Slate 对象以此管理生命周期 `FOnClicked` 点击事件委托(和其他各种事件) `SNew(WidgetType)` 创建控件 `SAssignNew(OutVar, WidgetType)` 创建并赋值给外部变量 `ChildSlot` 控件树中的槽位

三、常用控件一览

3.1 基础控件


// 文本
SNew(STextBlock)
    .Text(FText::FromString(TEXT("Hello Slate")))
    .ColorAndOpacity(FLinearColor::White)
    .Font(FAppStyle::GetFontStyle("BoldFont"))

// 按钮
SNew(SButton)
    .OnClicked(this, &SMyWidget::OnButtonClicked)
    [
        SNew(STextBlock).Text(FText::FromString("Click Me"))
    ]

// 图片
SNew(SImage)
    .Image(FCoreStyle::Get().GetBrush("WhiteTexture"))
    .ColorAndOpacity(FLinearColor::Blue)

3.2 容器控件

—— —— `SBox` 最简单容器,设定固定尺寸 `SConstraintCanvas` 绝对定位画布(类似 UMG Canvas) `SOverlay` 层叠布局(类似 UMG Overlay) `SHorizontalBox` 水平线性布局 `SVerticalBox` 垂直线性布局 `SWrapBox` 自动换行布局 `SScrollBox` 可滚动容器

3.3 输入控件


// 单行输入框
SNew(SEditableText)
    .Text(FText::FromString("Initial"))
    .OnTextChanged(this, &SMyWidget::OnTextChanged)

// 多行输入框
SNew(SEditableTextBox)
    .Text(FText::GetEmpty())

// 下拉框
SNew(SComboBox>)
    .OptionsSource(&Options)
    .OnGenerateWidget(this, &SMyWidget::HandleGenerateWidget)
    .OnSelectionChanged(this, &SMyWidget::HandleSelectionChanged)

四、布局系统详解

4.1 Slot 机制

Slate 的布局通过 Slot 实现。每个容器控件的子控件都有一个 Slot,Slot 控制子控件的位置和大小


SVerticalBox::FSlot& Slot = VerticalBox->AddSlot();
Slot
    .HAlign(HAlign_Center)   // 水平对齐
    .VAlign(VAlign_Center)   // 垂直对齐
    .Padding(10.0f)          // 内边距
    [
        SNew(STextBlock).Text(FText::FromString("Content"))
    ];

4.2 对齐规则


HAlign:  HAlign_Left | HAlign_Center | HAlign_Right | HAlign_Fill
VAlign:  VAlign_Top  | VAlign_Center | VAlign_Bottom | VAlign_Fill

4.3 自动Size vs 固定Size


// 固定尺寸
SNew(SBox)
    .WidthOverride(200.0f)
    .HeightOverride(100.0f)

// 填充父容器
SNew(SBox)
    .HAlign(HAlign_Fill)
    .VAlign(VAlign_Fill)

// 基于内容尺寸
SNew(SBox)
    .Content()
    [
        // 子控件自行决定尺寸
    ]

五、事件处理系统

5.1 常用事件类型

———- ———- `FOnClicked` 鼠标点击 `FOnPressed` / `FOnReleased` 按钮按下/释放 `FOnTextChanged` 文本内容改变 `FOnTextCommitted` 文本框回车提交 `FOnMouseEnter` / `FOnMouseLeave` 鼠标进入/离开 `FOnCheckStateChanged` CheckBox 状态改变

5.2 事件处理示例


// 在 Construct 中绑定
SNew(SButton)
    .OnClicked(this, &SMyWidget::HandleButtonClicked)
    [
        SNew(STextBlock).Text(FText::FromString("Click"))
    ]

// 声明处理函数
FReply SMyWidget::HandleButtonClicked()
{
    UE_LOG(LogTemp, Warning, TEXT("Button clicked!"));
    // 返回 FReply::Handled() 表示事件已处理
    // 返回 FReply::Unhandled() 表示事件继续传递
    return FReply::Handled();
}

六、Styling 与外观

6.1 使用编辑器样式


// 使用编辑器内置样式
STextBlock().Font(FAppStyle::GetFontStyle("HeaderFont"))
SButton().ButtonStyle(FAppStyle::Get(), "PrimaryButton")

6.2 自定义样式集


// 定义样式(通常在 .h 中声明)
const FSlateBrush* MyImage = FCoreStyle::Get().GetBrush("MyPlugin.Image");

// 使用
SImage().Image(MyImage)

七、自定义 SWidget 完整示例

7.1 头文件


#pragma once
#include "CoreMinimal.h"
#include "Widgets/SCompoundWidget.h"

class FMyPluginModule;

class SMyCustomWidget : public SCompoundWidget
{
public:
    SLATE_BEGIN_ARGS(SMyCustomWidget)
        SLATE_ATTRIBUTE(FText, DisplayText)
        SLATE_EVENT(FOnClicked, OnClick)
    SLATE_END_ARGS()

    // 构造器,BuildStyle 替换旧版 OnGenerateStyle
    void Construct(const FArguments& InArgs);

private:
    FReply HandleClick();
    TAttribute DisplayText;
    FOnClicked OnClick;
};

7.2 源文件


#include "SMyCustomWidget.h"
#include "Widgets/Text/STextBlock.h"
#include "Widgets/Buttons/SButton.h"

void SMyCustomWidget::Construct(const FArguments& InArgs)
{
    DisplayText = InArgs._DisplayText;
    OnClick = InArgs._OnClick;

    ChildSlot
    [
        SNew(SButton)
        .OnClicked(this, &SMyCustomWidget::HandleClick)
        [
            SNew(STextBlock)
            .Text(DisplayText)
            .Font(FAppStyle::GetFontStyle("BoldFont"))
        ]
    ];
}

FReply SMyCustomWidget::HandleClick()
{
    OnClick.ExecuteIfBound();
    return FReply::Handled();
}

八、性能优化技巧

8.1 避免每帧重建


// ❌ 错误:每帧创建新对象
void SMyWidget::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime)
{
        MyTextBlock->SetText(FText::FromString(GetNewText())); // 每次都修改
}

// ✅ 正确:使用 TAttribute 自动追踪变化
TAttribute MyTextAttr; // 在 Construct 中绑定

8.2 懒加载大数据


// 使用 SListView 的 ListItemSource 懒加载
TArray> Items;
TSharedRef>> ListView =
    SNew(SListView>)
    .ItemHeight(40)
    .ListDataSource(&Items)
    .OnGenerateRow(this, &SMyWidget::HandleGenerateRow);

8.3 缓存几何信息


// 在 Tick 中缓存,不要每帧计算
void SMyWidget::Tick(const FGeometry& AllottedGeometry, ...)
{
    CachedGeometry = AllottedGeometry;
    // 使用 CachedGeometry 而非每帧重新获取
}

九、调试工具

工具 快捷键/方法 用途 —— ————- —— Widget Reflector `Ctrl + Shift + W`(Editor内) 实时查看控件树、可视化布局 Slate Inspector `Slate.Inspector 1`(Console) 查看控件属性和布局信息 CVar 日志 `Slate.ShowDebug 1` 控制台输出 Slate 调试信息

// 代码中日志
UE_LOG(LogSlate, Log, TEXT("Widget constructed: %s"), *WidgetName);

十、学习建议

1. 阅读引擎源码:`Engine/Source/Runtime/Slate/Public/Widgets/` 下的 SButton、STextBlock、SImage 等基础控件
2. 从 UMG 入手:先在 Designer 中拖拽熟悉各种控件,理解其 Slate 对应物
3. 尝试自定义控件:从 SCompoundWidget 继承,组合现有控件
4. 理解声明周期:区分 `Construct`(构建)、`Tick`(每帧)、`OnMouse…`(事件)三个阶段
5. 善用 Attribute:`TAttribute` 是 Slate 响应式编程的核心

下一篇:《UE5 UMG 完全指南:从入门到进阶》将详解 UMG 编辑器的使用、动画系统、事件绑定与 C++ 联动。

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部