HarmonyOS ArkUI×display:折叠态切换盘点草稿一致性【鸿蒙心迹】
盘点现场最怕的不是屏幕从窄变宽,而是录入到一半,界面重排以后,刚填的数字还在不在。一个仓库复核页面通常只有几个字段:物料编码、数量、备注,以及尚未提交的草稿状态。但当折叠屏从单栏变成双栏,重新创建页面、给子组件换一份默认值,或者把折叠事件误当成“重新初始化”,都可能让编辑过程断掉。本文以 FoldLedger 的 DraftPage 为例,集中解决一个问题:设备形态可以变化,业务草稿不能跟着换身份。示例草稿 PD-042,物料 BX-204,数量 12,备注 外箱压痕。这些是为了说明状态关系而设定的演示数据,不是实际仓库记录,也不是设备测试结果。
## 一、先把折叠状态和可用宽度分开折叠屏适配容易出现一个误判:收到“展开”事件,就直接把布局切成双栏。实际上,折叠状态描述的是设备机械形态,可用于理解交互变化;界面真正可用的尺寸,还要受到当前窗口、分屏、多窗、横竖屏以及容器约束的影响。展开不等于页面一定有足够的宽度,折叠也不保证只剩一种窗口尺寸。华为的折叠屏开发资料给出了 display.isFoldable()、display.getFoldStatus() 与 display.on('foldStatusChange', callback)。这里用系统事件更新设备形态标签,但不让事件直接改写盘点内容。是否显示双栏,则交给页面根容器的 onAreaChange,通过实际区域宽度判断。这样设计还有一个好处:普通直板机或平板可以沿用宽度规则,不必制造“伪折叠”状态。目标页面有三个独立层次:第一层是业务草稿,包含草稿编号、SKU、数量和备注;第二层是设备观察值,例如展开、折叠或未知;第三层是展示模式,即单栏编辑或双栏校对。只有第一层会被“保存草稿”写入业务快照。后两层是可随时重算的派生状态,不应反向覆盖业务字段。## 二、先稳住数据,再谈组件树示例不采用在两种布局中各维护一份表单的做法。两个 TextInput 看起来像是同一字段,实际上若分别初始化,很可能出现单栏已经改为 12、双栏还停在初始数字的情况。一个更容易检查的方式,是让主页面持有同一份草稿数据,任何输入都只通过一个更新入口落到这份对象上。下面先给出草稿模型和更新逻辑。这段代码解决的不是持久化,而是在页面仍存活时保持表单值一致。为了触发状态观察,把对象整体替换,避免依赖嵌套对象原地修改带来的更新歧义。tsinterface CountDraft { draftId: string; sku: string; quantity: string; note: string; dirty: boolean;}// DraftPage 组件内的状态与方法@State private draft: CountDraft = { draftId: 'PD-042', sku: 'BX-204', quantity: '12', note: '外箱压痕', dirty: false};@State private saved: boolean = true;private updateQuantity(value: string): void { if (!/^\d*$/.test(value)) { return; } this.draft = { ...this.draft, quantity: value, dirty: true }; this.saved = false;}````quantity` 先保存为字符串,是因为输入过程中可能短暂出现空值,此时立刻转换成数字会把用户尚未输入完的状态破坏掉。真正提交时再校验是否为正整数、是否超出业务上限。`dirty` 用来区分“改过”与“尚未改过”,并不等同于后台已经收到数据。示例初始 `saved=true` 仅代表这份演示草稿已经在页面内暂存;离开进程后的恢复能力尚未提供。要特别强调:`@State` 不是数据库,也不是业务事务。页面销毁、系统回收或应用被清理时,单纯依赖组件内存无法保证数据不丢。若产品要实现真正的跨进程草稿恢复,应另行接入合适的本地存储,并设计草稿 ID、版本号、提交确认和冲突解决。本文刻意不把这件事写成已经完成的能力。## 三、监听折叠,但不让回调碰数量折叠监听属于页面可见生命周期内的观察工作。下面的片段展示注册和解绑的一对操作,展示状态通过枚举判断,无法识别时保留“未知”。回调只写设备标签和诊断信息,不会重新生成 `draft`。这就是“草稿一致性”的第一道边界。tsimport { display } from ‘@kit.ArkUI’;// DraftPage 组件内@State private foldLabel: string = ‘未知’;private onFoldChanged = (status: display.FoldStatus): void => { this.foldLabel = status === display.FoldStatus.FOLD_STATUS_FOLDED ? ‘折叠态’ : status === display.FoldStatus.FOLD_STATUS_EXPANDED ? ‘展开态’ : ‘其他形态’; console.info([FoldLedger] foldStatusChange draftId=${this.draft.draftId});};aboutToAppear(): void { if (display.isFoldable()) { this.onFoldChanged(display.getFoldStatus()); display.on(‘foldStatusChange’, this.onFoldChanged); }}aboutToDisappear(): void { if (display.isFoldable()) { display.off(‘foldStatusChange’, this.onFoldChanged); }}注册回调时要保存同一个函数引用,不能每次用一个新的匿名箭头函数,再期待卸载时自动找到它。重复订阅会让相同事件触发多次,造成日志膨胀,甚至出现页面已不显示却仍尝试操作状态的问题。若设备能力不支持,页面按一般宽度自适应工作即可。生产代码还要依据目标 SDK 的错误类型对监听注册失败做捕获和日志归类,不能因为一个设备事件影响输入操作。文中写出的事件日志是**预期的调试样例**,不是已从设备采集的数据。开发环境配图亦为演示合成图,用于标识该查看哪个回调。不要根据配图右侧的模拟器外观推断曾完成真实打包或部署。## 四、双栏的判断在根容器,不在硬件枚举界面核心只需要一道宽度门槛。假设 FoldLedger 在可用内容宽度达到 **600vp** 时展示双栏校对,否则保持单栏编辑。这是该 Demo 的布局设计值,不是 HarmonyOS 对所有应用统一规定的“折叠断点”。业务方可以根据字段长度、字体缩放和辅助功能再做调整。第三段代码展示布局监听和统一表单的思路。`onAreaChange` 是组件上的通用事件,传入的区域变化来自实际布局;不能把它写成 `display` 的方法,更不能把一个系统回调对象当成页面宽度。双栏只改变空间分配,输入组件绑定的仍是同一份 `draft`。ts@State private contentWidth: number = 0;@State private layoutMode: string = ‘单栏编辑’;@Builder private quantityField() { TextInput({ text: this.draft.quantity }) .onChange((value: string) => this.updateQuantity(value));}build() { Column() { Text(‘盘点草稿’); Text(${this.draft.draftId} · ${this.layoutMode}); if (this.contentWidth >= 600) { Row() { Text(SKU ${this.draft.sku}).layoutWeight(1); this.quantityField(); } } else { Text(SKU ${this.draft.sku}); this.quantityField(); } Text(this.draft.note); } .width(‘100%’) .onAreaChange((_oldArea: Area, newArea: Area) => { this.contentWidth = Number(newArea.width); this.layoutMode = this.contentWidth >= 600 ? ‘双栏校对’ : ‘单栏编辑’; });}```这一段是用于解释布局决策的组件内核心节选;实际项目还要为输入框设置合理宽度、焦点处理和无障碍文本,并把备注输入与保存按钮接到相同的数据模型上。重排前后可能发生输入焦点变化,这不能用“字段内容没丢”一句话掩盖。尤其使用条件渲染替换输入节点时,软键盘、光标位置和输入法合成状态都值得作为单独测试项。
## 五、用一个不变的草稿编号核对运行路径演示运行图把 PD-042、BX-204、数量 12、外箱压痕放在同一个页面上;布局标签是“双栏校对”,折叠状态标签是“展开态”。这几个值同时存在,目的不是证明某款真机必然显示双栏,而是给代码审查和图片核对一个固定样本。建议检查顺序如下:先在单栏修改数量,确认 draft.quantity 的唯一来源;再改变窗口宽度,观察 onAreaChange 和布局名称;最后在支持折叠状态事件的设备上改变形态,确认日志出现 foldStatusChange draftId=PD-042,且不存在把数量改回默认值的初始化代码。截图中 area=720vp layout=dual 与 saveDraft draftId=PD-042 qty=12 为预设日志格式,不能当成此次实际 HiLog 抓取证明。
点击“保存草稿”时,演示层可以生成一个当前字段的快照,并把 UI 状态设为“已暂存”。实际工程应将保存动作拆成“本地写入成功”“待同步”“服务器确认”三个可区分阶段,避免按钮刚按下就误提示远端已保存。草稿重复提交时,还应依赖草稿 ID 与业务版本控制,而不是用布局状态、页面重建次数或时间字符串充当去重依据。## 六、真正需要验证的边界其一,展开态下仍可能运行在窄窗口,布局门槛必须由内容容器宽度决定;其二,三折叠设备的状态枚举更复杂,不能把所有非折叠态都当作完全展开;其三,设备能力查询与事件监听都应有异常兜底;其四,页面内存、磁盘存储和服务端提交是三个不同等级的可靠性承诺。若要进一步提高可靠性,可以把草稿状态提升到页面之外的专用状态持有层,并对存储失败、进程杀死恢复、字号放大、双窗口缩放进行验证。这里不列出虚构耗时、通过率或设备兼容数量。最终的技术判断很简单:折叠变化是视图事件,草稿修改是业务事件,两者不要共用“初始化”入口。界面允许重排,字段身份必须稳定。官方参考:- 华为:折叠屏状态监听- 华为:折叠屏开发最佳实践- 华为:ArkUI onAreaChange 常见问题说明:文章中的 Demo、数据、HiLog 文字和配图均为设计演示,尚不代表真实设备上已完成编译和功能验证。
更多推荐




所有评论(0)