用途
Makepad 2.0 布局系统技能,用于理解和使用 Makepad 的布局机制。Makepad 采用的是「布局乌龟(layout turtle)」系统,而不是 CSS flexbox,也不是 CSS grid。乌龟会逐个走过子元素,并根据两个核心概念摆放每个控件:
- Walk:控件如何确定自身尺寸(width、height、margin)
- Layout:容器如何排列其子元素(flow、spacing、padding、align)
每个容器控件(View、SolidView、RoundedView、ScrollYView 等)同时具备 Walk 属性(自身尺寸)和 Layout 属性(如何布局子元素)。
Walk 系统(控件尺寸)
Walk 控制单个控件如何在父容器中占据空间。width / height 的取值如下:
width: Fill:填满剩余水平空间(默认)width: Fit:收缩以贴合内容width: 200:固定 200 像素width: Fill{min: 100 max: 500}:带约束填满width: Fit{max: Abs(300)}:贴合内容,上限 300pxheight: Fill:填满剩余垂直空间(默认)height: Fit:收缩以贴合内容height: 100:固定 100 像素
关于容器的 height: Fit:文档将其称为 Makepad 中第一号布局 bug。默认高度是 Fill。当输出渲染在 Fit 容器内时,Fit 内部的 Fill 会产生循环依赖并解析为 0 像素,整个 UI 会不可见。规则是:除非父容器具有固定或 Fill 高度,否则始终在每个 View、SolidView、RoundedView 及类似容器上设置 height: Fit。
例外情况(此处可接受 height: Fill):固定高度父容器内部;位于最终到达已知尺寸(如 Window body)的 height: Fill 链内部;ScrollYView 始终使用 height: Fill,因为它必须填满父容器才能滚动。
margin 用于在控件外部添加空间,支持统一值、Inset 结构与 0.(注意浮点字面量的尾点)。
Layout 系统(子元素排列)
flow(方向):
flow: Right:从左到右,单行(默认),对应 flex-direction: rowflow: Down:从上到下,单列,对应 flex-direction: columnflow: Overlay:子元素堆叠,对应 position: absolute stackingflow: Flow.Right{wrap: true}:从左到右并换行,对应 flex-wrap: wrapflow: Flow.Down{wrap: true}:从上到下并换行,列换行
spacing 是子元素之间的间隙,单一数字统一应用。padding 是容器边缘与子元素之间的内部空间,支持统一值与 Inset 结构。
align(子元素对齐):在容器剩余空间内定位子元素,取值 0.0(起点)到 1.0(终点)。包括 Center(x:0.5 y:0.5)、HCenter(x:0.5 y:0.0)、VCenter(x:0.0 y:0.5)、TopLeft(x:0.0 y:0.0,默认),以及右上、左下、右下、底部居中等对应坐标写法。
clip_x / clip_y 控制溢出内容是否被裁剪。重要边界:clip_x: false / clip_y: false 只允许局部子元素在父容器外绘制,并不会把该子元素变成真正的窗口级覆盖层。如果 UI 元素是应独立于局部布局树浮动的弹出层/菜单/提示,应使用顶层 Modal/overlay owner,而不是依赖局部溢出。
覆盖层弹窗定位:在覆盖层(Modal、tooltip 层、popup owner)内部做弹窗式定位时,优先使用 walk.abs_pos,而非运行时修改 margin。margin 是布局间距,最适合微调常规流式子元素;walk.abs_pos 是用于覆盖层式摆放的显式乌龟锚点。button.area().clipped_rect(cx) 可获取触发器的实际屏幕空间矩形(包含 view_shift 与裁剪)。对于覆盖层内容,先计算弹窗的绝对屏幕空间目标,再写入 popup.walk.abs_pos = Some(dvec2(x, y))。经验法则:位于常规布局树内、仅需轻微溢出的弹窗用局部子元素加 clip_x/clip_y: false;锚定到按钮但视觉上位于组件之外的弹窗用顶层 overlay 加 walk.abs_pos。常见错误是用 script_apply_eval! 在覆盖层内容上推 margin.top / margin.left,并期望得到稳定的弹窗坐标,这常常产生误导性结果,因为仍在与布局协商,而不是显式锚定弹窗。
Inset 语法:Inset 类型同时用于 padding 和 margin,支持裸数字(四边统一)与 Inset{top: 10 bottom: 10 left: 20 right: 20} 结构写法。零值使用 0.(浮点字面量尾点)。可省略不需要的边,默认 0。padding 在容器内部,margin 在容器外部。
滚动容器
Makepad 提供三种可滚动视图变体,继承所有 View 属性并增加滚动条行为:
- ScrollYView:仅垂直,用于长列表、页面内容
- ScrollXView:仅水平,用于宽表格、时间线
- ScrollXYView:双轴,用于地图、画布、大型内容
使用时注意:可滚动视图使用 height: Fill(不是 height: Fit),因为它们需要固定视口才能滚动,内部内容会增长超出视口。ScrollYView 是 90% 场景需要的。
Filler(占位控件)
Filler{} 等价于 View{width: Fill height: Fill},用于把兄弟元素推开。关键规则:只在 width: Fit 的兄弟元素之间使用 Filler。不要将 Filler{} 放在 width: Fill 的兄弟元素旁边,两者会争夺剩余空间并各分一半,导致文本被裁剪。正确的替代方式是让 width: Fill 的元素自然推动 Fit 兄弟元素。
常见布局模式
文档给出了多种模式:垂直页面布局、水平工具栏、带换行的卡片网格、居中内容、分栏面板(固定侧边栏与 Splitter 可调整两种写法)、固定头部 + 可滚动主体 + 固定底部,以及覆盖层/Modal 定位。这些模式均以 Makepad 代码示例展示,涵盖 SolidView、RoundedView、ButtonFlatter、ButtonFlat、Button、Hr、Splitter、SplitterAxis、SplitterAlign 等控件与属性写法。