Slate 实践
自动关联目录:Slate 实践
1. 定位
Slate 是 UE 底层的 C++ UI 框架,编辑器自身就是用它写的。UMG 建立在它之上。
一句话定位:绝大多数游戏 UI 用 UMG 就够;只有两类场景需要直接写 Slate——编辑器扩展,以及需要极致性能/自定义绘制的控件。
2. 结构
SWidget(Slate 层)
├── SCompoundWidget 有一个子控件
├── SPanel 有多个子控件(布局容器)
├── SLeafWidget 无子控件
└── STextBlock / SImage / SButton ...| 概念 | 说明 |
|---|---|
SWidget | 基类 |
| 声明式语法 | SNew(STextBlock).Text(...) |
Construct | Slate 侧的构造(在 FArguments 里) |
Tick | 每帧(需显式启用) |
OnPaint | 自定义绘制 |
ComputeDesiredSize | 自定义布局尺寸 |
SNew(SVerticalBox)
+ SVerticalBox::Slot().AutoHeight()
[ SNew(STextBlock).Text(FText::FromString(TEXT("Hi"))) ]
+ SVerticalBox::Slot().FillHeight(1.f)
[ SNew(SButton).OnClicked(this, &SMyWidget::OnClick) ]3. 什么时候用 Slate
| 场景 | 用 |
|---|---|
| 常规游戏 UI | UMG |
| 编辑器扩展 | Slate(见 Editor Extension) |
| 高性能长列表 | Slate + 虚拟化,或 UMG 的 ListView |
| 自定义绘制 | Slate(OnPaint) |
| 需要与 UObject/GC 集成 | UMG |
4. 与 UMG 的关系
| Slate | UMG | |
|---|---|---|
| 层 | 底层 C++ | UObject 封装 |
| 编辑 | 代码 | 可视化 |
| GC | 不参与 | 参与 |
| 性能 | 更高 | 多一层 |
| 上手 | 难 | 容易 |
UMG 的 UWidget 内部就持有 SWidget——两者不是竞争关系,而是包装关系。想在 UMG 里嵌入自定义 Slate,可以重写 RebuildWidget()。
5. 代价与权衡
| 设计 | 收益 | 代价 | 什么时候不该用 |
|---|---|---|---|
| Slate | 性能最高、可控 | 代码量大、无可视化、无 GC | 常规 UI 不该用 |
| UMG | 可视化、蓝图、GC | 多一层 | 性能极致时可考虑 Slate |
| 自定义 OnPaint | 任意绘制 | 要自己处理布局与失效 | 能用内置控件就不要 |
| Slate Tick | 每帧更新 | 每帧成本 | 尽量事件驱动 |
6. 踩坑与排查
| 坑 | 现象 | 怎么验证 |
|---|---|---|
| 用 Slate 写常规 UI | 开发效率低 | 改用 UMG |
| Slate 里持有 UObject 裸指针 | 崩溃(见 GC) | 用 TWeakObjectPtr |
| 自定义 OnPaint 忘记失效 | 不刷新 | 正确触发 Invalidate |
| Slate Tick 全开 | 每帧成本 | 只给必要的开 |
| 布局没实现 ComputeDesiredSize | 尺寸为 0 | 实现它 |
| 在 Slate 里做游戏逻辑 | 与 UMG 同理 | 见 Security |
7. 排查顺序
1. 先确认是不是真的需要 Slate(常规 UI 用 UMG)
2. 布局问题 → 检查 Slot 与 ComputeDesiredSize
3. 不刷新 → Invalidate
4. 崩溃 → 是否持有 UObject 裸指针
5. 性能 → 减少 Tick,检查 OnPaint 复杂度参考
- UMG 深入 · UI 性能 ·
Editor Extension分支 - GC 与对象生命周期
许可协议:CC BY
作者:Davids
本文链接:https://hustjjd.github.io/dd46c867.html
更新于:2026年10月10日