做双栏业务页时,有一种布局特别容易误判:窗口已经足够宽,右侧详情却仍然被挤成一条细长的纸带。财务审批系统尤其明显,列表与详情同时出现之后,右侧可能只拿到三百多 vp;按照整个窗口判断“这是大屏”,往里面塞横向字段和两个并排按钮,反而让关键信息不完整。这篇讨论的不是如何开启平行视界,而是双页面已经存在时,详情页如何按自己真正分到的空间决定呈现策略。示例项目叫 SplitReceipt,页面是 ExpenseDetailPane,审核单 BILL-084、金额 ¥1,280、附件五项,其中三项已核对、两项待核对。全文数据均为设计好的演示样本,没有宣称真机测出特定窗口宽度。## 一、大窗口不等于大详情栏假定展开设备的应用窗口宽约九百多 vp,左侧保留报销单列表,右侧还有分隔间距、卡片内边距。此时真正供详情控件使用的空间,可能只有 316vp。如果页面仍用窗口级断点判定横排,会发生三个问题:字段标题被截断、金额信息和审批原因竞争一行、确认按钮被挤到屏外。用户看到的是排版故障,工程根因却是观测尺寸的层级错了。ArkUI 的 GridRow 适合宏观栅格;ContainerReader 则是容器级尺寸感知。官方容器断点文档在 2026 年 9 月更新,说明该组件从 API 26.0.0 开始提供,能够把容器尺寸和宽度断点双向绑定到状态变量。它不负责替应用建立左右页面关系,也不保证任何设备自动进入平行视界。本文假设页面关系已经由应用现有结构处理,只讨论详情内部的布局合同。我给详情区域定了两个业务约束:无论怎么变窄,金额与当前审核进度必须保留;“提交复核”始终取决于附件核对结果,不能因卡片被折叠或隐藏而变成可点。这个约束决定了代码里必须分开存放数据状态与布局状态。## 二、先把提交权限放在视图之外第一段代码解决的不是断点,而是复核门禁。五份附件中只认按稳定 ID 核对的记录;布局压缩时可以少显示解释文本,但不能少算附件,也不能用按钮视觉状态代替业务判断。arktsexport interface ReceiptItem { id: string; checked: boolean;}export interface ReviewSummary { checked: number; pending: number; canSubmit: boolean;}export function summarize(items: ReceiptItem[]): ReviewSummary { const checked = items.filter((item: ReceiptItem) => item.checked).length; const pending = items.length - checked; return { checked, pending, canSubmit: items.length > 0 && pending === 0 };}````ReceiptItem.id` 是业务身份,不是 UI 列表的顺序号。当前演示输入为五项,运行这段纯函数应得到 `checked=3`、`pending=2`、`canSubmit=false`。这里的“应得到”是逻辑推演,不是模拟器实测。后续数据可能来自 Repository 或服务端,但门禁放在同一处,避免左右页面各自复制判断后出现不同结果。错误实现往往只在视觉分支里把“两个待核对”那一行隐藏,却忘记保留提交判断。等到用户缩小窗口,摘要被折起,按钮又在另一处根据旧状态启用,这就从 UI 问题变成业务风险。我的做法是让 UI 从摘要对象读取状态,不让断点参与 `canSubmit` 的计算。## 三、详情页感知自己的剩余宽度接着才使用 `ContainerReader`。下面是一段可嵌入项目的 ArkUI 页面骨架:父容器有明确高度,`size` 与 `widthBreakpoint` 都用 `@State` 初始化,并带 `!!` 完成双向绑定。演示将 `360vp` 与 `600vp` 作为业务断点,当前 `316vp` 属于 `WIDTH_XS`,所以字段改为纵向叠放。arktsimport { ContainerReader, Size } from ‘@kit.ArkUI’;@Entry@Componentstruct ExpenseDetailPane { @State paneSize: Size = { width: 0, height: 0 }; @State paneBp: WidthBreakpoint = WidthBreakpoint.WIDTH_MD; @State checkedCount: number = 3; private readonly totalCount: number = 5; build() { Column({ space: 12 }) { Text(‘BILL-084 · 报销复核’).fontSize(22) ContainerReader({ size: this.paneSize!!, widthBreakpoint: this.paneBp!! }) { Column({ space: 12 }) { Text(详情栏宽度:${Math.round(this.paneSize.width)}vp) if (this.paneBp === WidthBreakpoint.WIDTH_XS) { Column({ space: 8 }) { Text(‘报销金额 ¥1,280’) Text(附件核对 ${this.checkedCount}/${this.totalCount}) }.width(‘100%’) } else { Row({ space: 16 }) { Text(‘报销金额 ¥1,280’) Text(附件核对 ${this.checkedCount}/${this.totalCount}) } } }.width(‘100%’) } .breakpointConfig({ width: [360, 600] }) .height(300) Button(‘提交复核’).enabled(this.checkedCount === this.totalCount) }.padding(16).width(‘100%’) }}这段示例故意没有伪造 EasyGo 的配置,也没有把 `ContainerReader` 当成改变窗口宽度的 API。它只读来自布局系统的实际容器大小。官方文档还特别说明:`size` 的写入不能用于强行设置组件尺寸;尺寸由父布局确认,因此容器的父级必须有明确可计算的约束。示例 `.height(300)` 是为最小演示消除循环测量风险,实际产品可由稳定的剩余空间布局取代。这里还有一个细节值得单独检查:`WIDTH_XS` 是断点枚举,不应靠手算窗口总宽来猜。容器刚创建时 `paneSize` 初始为零,界面可能先出现一种初始排版,随后才收到布局测量结果。正式实现可以在宽度为零时显示轻量占位,而不要把零宽度当作用户真的切到极窄窗口。断点由 `breakpointConfig` 按配置区间计算,门禁则继续由核对数量负责。![](https://i-blog.csdnimg.cn/direct/2fb8a02ed96f4d33a5d1ff334645ad0b.png)## 四、诊断只记录必要的状态如果视觉上仍然混乱,我不会第一时间调整字体。我会先确认右侧详情真正测得多少空间、是否跨过业务断点、按钮是否与附件数量一致。调试数据必须和页面输入来自同一时刻,不能把上一次展开态的截图与这一次折叠态的日志拼在一起。第三段代码给演示页面加入一个手动诊断动作。它只打印业务 ID、局部宽度、枚举值、核对数量与提交门禁,不输出附件内容、人员名字或金额凭证原文。arktsprivate logSnapshot(): void { const width: number = Math.round(this.paneSize.width); const pending: number = this.totalCount - this.checkedCount; const bp: string = this.paneBp === WidthBreakpoint.WIDTH_XS ? ‘XS’ : this.paneBp === WidthBreakpoint.WIDTH_SM ? ‘SM’ : ‘MD+’; console.info(SplitReceipt BILL-084 width=${width}vp bp=${bp} + checked=${this.checkedCount}/5 pending=${pending} + submit=${pending === 0});}```将此方法放进上面的组件内,再把它绑定到测试用“输出布局快照”按钮即可。演示预期日志为 SplitReceipt BILL-084 width=316vp bp=XS checked=3/5 pending=2 submit=false,时间可记作 18:18。这串文字只是预设验证样本,必须在 DevEco Studio 真实运行后才能称为 HiLog 采集结果;合成的 IDE 配图不会变成性能证据。实际项目应先记录一次宽度为 316vp 的窄栏,再尝试 420vp 和 640vp。检查维度不是“三种宽度的画面都好看”,而是字段是否可达、核对计数是否固定、禁用状态是否持续。当宽度扩张到横排阈值后,信息可能移动位置,但 BILL-084 不能因重新布局而变成另一张单据,页面局部状态更不能清空仓库里的审核对象。## 五、把“看见多少”与“允许做什么”分开验收在手机竖屏演示图里,我只呈现一栏详情:顶部完整状态栏,下方显示审核单、金额、五项附件核对进度与禁用操作。它的角色是说明局部组件在窄空间中的预期结果,不是证明已经通过折叠屏的平行视界兼容测试。若要证明两栏协同,还需要在对应设备或多窗口环境里额外录屏、检查页面栈与返回动作。几个反例容易暴露设计边界。第一,父组件本身靠子组件撑开高度,而子组件又依赖 ContainerReader 反向计算尺寸,容易得到不可预期的测量结果;要先让父布局有确定约束。第二,同一行附件如果只凭 index 标记核对,列表刷新排序后可能把已核对状态给错附件;稳定 id 才是正确依据。第三,断点切换不能触发提交事件,尤其不能在 build 或可观察布局变化中调用具有副作用的业务方法。最后也别把“适配完成”简化成截图通过。验证矩阵至少包括小窗、展开、分屏、横竖切换、系统字号放大,以及审核对象加载中与失败时的占位表现。大字体下即便容器已经超过 360vp,横排字段仍可能不够,产品可以在容器断点之外叠加可访问性策略;业务门禁则保持相同结果。我更愿意把 ContainerReader 看成详情页的空间输入,而不是它的“业务导演”。它能够告诉组件真实可用的范围,却不应该替业务决定谁有审批权限、哪一单正被审核、附件是否核对完成。这个边界守住了,平行视界中的局部重排才不会把复核流程一起重排。## 六、适用条件与资料本文只给出 ArkUI 容器感知和业务门禁的示例结构。ContainerReader 从 API 26.0.0 提供,接入前应检查工程的目标 SDK、DevEco Studio 版本与设备能力;如果项目尚未使用支持版本,应维持原有明确尺寸布局,不要为了示例硬写尚不可用的组件。本文没有完成 SDK 编译、真实设备验证、业务账号联调或平行视界配置验证,配图只用于解释预期界面和调试路径。官方参考:ArkUI 容器断点 ContainerReader、HarmonyOS 多形态应用适配。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐