// 测量与绘制依赖分离:改颜色应复用尺寸缓存,改模型宽度才需要重新测量。 // ViewportBand 还显式读取实际页面视口,使原生 resize 可通过依赖触发重测。 // 只负责测量需要的宽度,和绘制颜色分成两个业务对象以便观察独立失效。 class WidthModel { width: Number // 点击把模型宽度置为 260;源 measure 读取过该字段,缓存因此失效。 // 按钮 click 的 Event 回调,只写 WidthModel.width;后续是否重测由已记录的真实读取失效决定。 function expand(self: WidthModel, event: Event): Unit { self.width = 260 } } // 保存 paint 使用的颜色,不参与 CachedRect 的测量。 class Tint { color: String // 只改颜色;正常情况下需重绘而不重新执行无关源测量。 // 另一按钮的 Event 回调只写 Tint.color,不改 dimensions,避免用无关模型写入混淆测量依赖。 function blue(self: Tint, event: Event): Unit { self.color = "#526AC7" } } // 原生矩形的尺寸/颜色策略分别由源协议覆盖,业务模型通过字段持有。 class CachedRect: RectBlock { // CachedRect 引用两个不同策略对象;measure 读尺寸对象,paint 读颜色对象,各阶段依赖分开记录。 dimensions: WidthModel tint: Tint // 读取 dimensions.width 返回固定高 60;实际读观察由运行时缓存记录,不手工声明依赖表。 // 只读测量由 source_layout 调用,self 是共享矩形,mount/constraints 是当前出现输入,不写 geometry。 function measure(self: CachedRect, mount: Mount, constraints: Constraints): MeasureResult { return MeasureResult(self.dimensions.width, 60) } // 复用原生矩形命令,再改新命令的颜色;修改新结果被允许,但 paint 不能修改已有业务对象。 function paint(self: CachedRect, mount: Mount, geometry: Bounds): DisplayList { // 源 paint 由 source_paint 调用,显式委托基类得到本轮新 DisplayList,不在这里发输入事件或改变 Page。 drawing = RectBlock.paint(self, mount, geometry) // 修改的是新分配命令的颜色字段,再由宿主统一解码校验;self.tint 仍只读。 drawing.commands.at(0).color = self.tint.color return drawing } } // 宽度来自 ui.viewport 的当前逻辑页面区域,显示窗口变化也能成为测量依赖。 class ViewportBand: RectBlock { // 返回可用视口宽度,最终仍服从父容器约束;外层 padding 会减少分配宽度。 // ui.viewport 取当前窗口逻辑页面范围,实际返回尺寸还会受父级更窄的 Constraints 约束。 function measure(self: ViewportBand, mount: Mount, constraints: Constraints): MeasureResult { return MeasureResult(ui.viewport().width, 24) } } // 创建相互独立的宽度/颜色模型并绑定两个按钮,用相同对象观察缓存与可见结果。 dimensions = WidthModel(200) tint = Tint("#ED6A5A") // 源字段 dimensions/tint 放在原生构造参数后,RectBlock 的默认尺寸不是这个覆盖 measure 的最终输出。 rect = CachedRect(80, 20, 0, "#ED6A5A", dimensions, tint) band = ViewportBand(80, 24, 0, "#237A45") blue = Button("只改绘制颜色") expand = Button("修改测量依赖") // 保存两个监听连接,颜色按钮绑定 tint,宽度按钮绑定 dimensions,不把 UI 事件对象用作缓存 owner。 blueConnection = blue.on("click", tint.blue) expandConnection = expand.on("click", dimensions.expand) // 根组合同时展示 viewport 依赖和业务尺寸依赖;按钮回调完成后宿主统一刷新,不在点击方法里手工重排。 root = Column(24, 16, TextBlock("改变颜色保留测量缓存;改变宽度重新测量"), band, rect, blue, expand) page = Page() page.render(root)