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 也好看。