// 盒模型组合:容器与 Page/相机独立,border-box 尺寸、padding、margin 和对齐分别参与布局。 // 同一文字共享内容,在左右不同有限分配中各自换行;外层 Overlay 负责叠放固定角标并裁剪溢出。 // 内部布局基于容器自己的约束;Page 和相机只提供外部展示/投影上下文。 // 文字 boxWidth=fill 占父分配的可用宽度,marginBottom 在文字边框盒外参与排布。 shared = TextBlock("同一个对象可以有多个 Mount。每个位置分别测量、换行和对齐。", 2) // fill 是共享对象的布局策略,每次出现仍从各自父约束得到实际宽度;不把首次测量宽度保存回 shared。 shared.boxWidth = "fill" shared.marginBottom = 8 // 左 Column 使用 fill、min/max 宽度限制和四边边框;非对称 paddingLeft 覆盖统一 padding。 left = Column(16, 12, TextBlock("Row / Column", 2), shared, Button("继续探索")) left.boxWidth = "fill" // 给父 Row 的分配加上下限/上限,min/max 是 border-box 约束,不是原生窗口宽度。 left.minWidth = 180 left.maxWidth = 360 // 四边分别设置厚度,测量/安排时边框与 padding 占内容外空间;颜色只影响绘制。 left.borderLeft = 2 left.borderTop = 2 left.borderRight = 2 left.borderBottom = 2 left.borderColor = "#CBD5E1" left.paddingLeft = 24 // Column 的交叉轴为横轴,未自行覆盖对齐的孩子按 center 排;共享文字还有 fill 自身宽度策略。 left.crossAlign = "center" // 右 Column 也引用同一 shared,但最大宽只有 240,因此对应 Mount 的换行高度可以不同。 right = Column(16, 12, TextBlock("共享内容,独立排版", 2), shared) right.boxWidth = "fill" right.maxWidth = 240 // 这里 end 仅选择右容器内的交叉轴位置,不改变 shared 业务对象在左容器的对齐。 right.crossAlign = "end" // Row 分配有限 760 主轴空间,扣 padding/gap 后在两侧 fill 子项之间分配并服从上限。 content = Row(24, 24, left, right) content.boxWidth = 760 // Row 的交叉轴为纵轴,start 让左右两列按可用上侧对齐,列高仍来自各自文字换行测量。 content.crossAlign = "start" // 角标是 Overlay 的另一子项,alignSelf 与 margin 控制它在容器交叉轴上的位置。 badge = TextBlock("Endorphin · layout") badge.marginRight = 12 badge.marginBottom = 12 // 子项显式对齐覆盖父级默认交叉轴对齐,margin 保留在边框盒外,不作为文字内容绘制。 badge.alignSelf = "end" // 固定 800x400 的 Overlay 不按线性顺序挤开兄弟,overflow=clip 同时约束绘制和命中。 surface = Overlay(0, 0, content, badge) surface.boxWidth = 800 surface.boxHeight = 400 // Overlay 的主轴对齐参与各子项在同一区域的分配,不像 Column 那样把 content 和 badge 顺序堆叠。 surface.mainAlign = "end" // overflow 策略由宿主投影成子裁剪,超出有限表面的文字/按钮不能仅凭原布局盒穿透命中。 surface.overflow = "clip" // Page 只提供展示入口,根容器自身的盒模型规则不依赖页面导航方式。 page = Page() page.title = "嵌套盒模型" // 顶层脚本执行到这里请求展示完整对象组合;布局驱动随后按出现约束求解,再发布不可变绘制帧。 page.render(surface)