// 测量/排列协商示例:arrange 指定子宽后需重新换行测量,高度变化继续影响父容器和后继位置,直到整树稳定。 // paragraph 被两个容器共享;每个 Mount 使用独立约束,不能把新宽度写回共享文字状态。 // 保存第一个段落出现位置的分配宽度,按钮只改策略值。 class Policy { width: Number // 选择 280 逻辑像素宽度,段落变高,后继文字下移。 // narrow/wide 按钮事件回调更新同一 policy.width,只有持有该策略的 ArrangedColumn 读取它。 function narrow(self: Policy, event: Event): Unit { self.width = 280 } // 选择 560 逻辑像素宽度,段落变矮;另一个容器宽度不跟着改变。 function wide(self: Policy, event: Event): Unit { self.width = 560 } } // 在原生 Column 排列基础上覆盖第一个稳定子槽的宽度。 class ArrangedColumn: Column { // 布局共享策略模型,不保存段落的全局最终宽度;某个出现的约束/分配由 Plan 独立记录。 policy: Policy // 先取得包含全部子槽的 Arrangement,仅改第一子项分配;保留其他槽使排列验证完整。 function arrange(self: ArrangedColumn, mount: Mount, geometry: Bounds): Arrangement { // source_layout 的安排阶段调用覆盖方法,基类利用本轮孩子测量值生成包含全部稳定 slot 的临时结果。 result = Column.arrange(self, mount, geometry) // 只改返回的第一子槽 Bounds.width,宿主会验证槽完整性并据显式分配反推下一轮精确测量约束。 // at(0) 只用于挑选返回列表中的首项;该 Bounds 原有的稳定 slot 保持不变,宿主按 slot 而非列表下标关联孩子。 result.children.at(0).width = self.policy.width return result } } // 通过源 measure 改整个容器的期望宽度,以对比 arrange 分配路径。 class MeasuredColumn: Column { // MeasuredColumn 自有策略字段,不是共享 paragraph 的 boxWidth,也不复制段落内容。 width: Number // 调用原生测量后修改新结果 width;这个新结果不属于已有业务对象,允许在只读计算中填写。 function measure(self: MeasuredColumn, mount: Mount, constraints: Constraints): MeasureResult { // 测量阶段先委托基类求自然尺寸,再修改临时 MeasureResult;已有业务对象仍受只读限制。 result = Column.measure(self, mount, constraints) // 宿主读取这个新结果字段后还会按 Constraints 钳制;源返回 width 不等于绕过上层几何预算。 result.width = self.width return result } } // 两个容器使用同一个 paragraph,分别由 Policy=280 与 measure.width=360 约束。 policy = Policy(280) paragraph = TextBlock("源码 arrange 改变分配宽度后,文字会按实际宽度重新测量。增加的高度继续影响容器和相邻对象,直到整棵布局稳定后才发布。这里与下面使用的是同一个 TextBlock;每个 Mount 都有自己的约束与几何。同一套内存对象不需要复制业务状态,也不通过丢弃传播来结束更新。") tail = TextBlock("这一行跟随上方段落。") // 首个孩子是 paragraph,故 at(0) 修改的是它的分配;tail 的位置在重新测高与收敛后随段落高度更新。 arranged = ArrangedColumn(0, 12, paragraph, tail, policy) // 另一出现仍用同一 paragraph,但父测量策略为 360,与上面的 policy.width 独立。 measured = MeasuredColumn(0, 12, paragraph, TextBlock("这一段的宽度来自源码 measure。"), 360) narrow = Button("arrange 为 280") wide = Button("arrange 为 560") // 保留事件订阅引用,两个按钮调用同一 Policy 的不同方法。 narrowConnection = narrow.on("click", policy.narrow) wideConnection = wide.on("click", policy.wide) // 这两个父容器都在同一文档根,布局需要整树稳定再一起发布,不能先显示新宽度再补旧高度。 page = Page() page.title = "约束协商" page.render(Column(24, 16, Row(0, 12, narrow, wide), arranged, measured)) // 成功输入结束后宿主才消费原生窗口命令;窗口实际尺寸再回传为下一次布局约束。 ui.window().resize(850, 700) ui.window().setTitle("测量与排列直到稳定")