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 关键类型速查
—
三、常用控件一览
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 容器控件
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 常用事件类型
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 而非每帧重新获取
}
—
九、调试工具
// 代码中日志
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
—
下一篇:《UE5 UMG 完全指南:从入门到进阶》将详解 UMG 编辑器的使用、动画系统、事件绑定与 C++ 联动。