2.2 布局与排布:堆叠、网格与百分比
槽位的尺寸策略
容器(SVerticalBox/SHorizontalBox)的每个 Slot 有三种尺寸模式:
+ SVerticalBox::Slot()
.AutoHeight() // 按内容高度(按钮、文本行常见)
+ SVerticalBox::Slot()
.FillHeight(1.0f) // 占剩余空间的 1.0 份(与其他 Fill 按比例分)
+ SVerticalBox::Slot()
.MaxHeight(200.0f) // 与 FillHeight 配合,封顶
+ SVerticalBox::Slot()
.Padding(FMargin(8, 4, 8, 4)) // 内边距:左、上、右、下
+ SVerticalBox::Slot()
.HAlign(HAlign_Fill).VAlign(VAlign_Center) // 对齐
[
SNew(SButton)
]
理解的关键:Slate 布局是「先满足 Auto,再把剩余空间按 Fill 比例分」。所以一个工具面板的经典结构是:标题区(Auto)+ 列表区(Fill 1.0)+ 按钮区(Auto)。
常用布局容器
| 容器 | 用途 |
|---|---|
| SVerticalBox / SHorizontalBox | 最常用:一维堆叠 |
| SOverlay | Z 序堆叠(弹层、 loading 遮罩) |
| SConstraintCanvas | 绝对定位(类似 UMG Canvas Panel,编辑器 UI 少用) |
| SScrollBox | 滚动容器 |
| SGridPanel / SUniformGridPanel | 网格(SUniformGrid 等格大小) |
| SSplitter | 可拖拽分隔条(工具界面常用:左列表右详情) |
| SBox | 固定尺寸约束(MinDesiredWidth 等) |
经典工具面板布局
SOverlay(外层)
├── SVerticalBox(主列)
│ ├─ Auto: 标题 STextBlock
│ ├─ Auto: SHorizontalBox(筛选行:输入框 + 按钮)
│ ├─ Fill 1.0: SSplitter(两栏)
│ │ ├─ 左:SListView(资产列表)
│ │ └─ 右:详情 SBox
│ └─ Auto: SHorizontalBox(底部按钮行)
└── (可选)SOverlay Slot:Loading 遮罩
SNew(SOverlay)
+ SOverlay::Slot()[
SNew(SVerticalBox)
+ SVerticalBox::Slot().AutoHeight()[ SNew(STextBlock).Text(FText::FromString("标题")) ]
+ SVerticalBox::Slot().FillHeight(1.0f)[
SNew(SSplitter).Orientation(Orient_Horizontal)
+ SSplitter::Slot().Value(0.3f)[ LeftList ]
+ SSplitter::Slot().Value(0.7f)[ RightDetails ]
]
]
尺寸单位
Slate 尺寸单位约等于「像素 × DPI 缩放」,在普通显示器上近似像素。Padding/字号都用同一单位。不要用 UMG 的「锚点思维」(SConstraintCanvas 才有),Slate 大量靠「Fill 比例」做自适应。
DPI 缩放的坑
高 DPI 屏(4K/Retina)上字号和间距会被自动放大,这是好事;但有些自绘内容(OnPaint 里的手动绘制)不会自动缩放,需要乘 FSlateApplication::Get().GetApplicationScale()。工具 UI 一般不涉及,做自定义绘制时注意。
响应式
Slate 工具窗口大多是浮动窗口,用户会拖动改变大小。设计原则:
- 关键控件给
AutoHeight,列表区给Fill,窗口缩小时按钮始终可见 - 长文本用
SNew(STextBlock).AutoWrapText(true)而不是固定宽度 - 列表的
ItemHeight固定,虚拟列表渲染才稳
心得:布局阶段先用一行注释画出层级树(像上面那样),再翻译成代码——直接写嵌套的 SNew 很容易陷入「括号地狱」。层级树法能把 bug 率降一半,code review 也好看。
