在这里插入图片描述

一、过去多端开发的真实困境

做商用折叠触控终端、自助机、平板、PC多端项目最头疼的几件事:

  1. 一套业务要写多套页面,合拢、展开、悬停、分屏各一套布局,改需求要同步改全部,极易漏改、视觉不一致;
  2. 大量if判断屏幕尺寸,用屏幕尺寸做适配,一自由分屏、悬浮窗布局直接错乱;
  3. 悬停折痕靠手动padding避让,不同设备折痕高度不一样,总有按钮被挡住点不动;
  4. 折叠切换页面大面积闪白、列表滚动归零、输入框数据清空,用户体验差;
  5. 平行视界左右分栏共用全局状态,操作一边另一边数据乱跳,碰一碰弹窗永远卡在左侧;
  6. 低端工业机页面重复监听窗口、折叠事件,主线程阻塞,触控卡顿、长期运行闪退。

很多项目一开始图省事堆硬编码宽高、零散尺寸判断,后期迭代维护成本爆炸,折叠适配bug层出不穷。鸿蒙7完整补齐了栅格、折叠原生容器、全局状态观测体系,真正实现一套代码跑全形态、全终端。

二、核心思路:以窗口断点栅格为唯一适配基准

1. 统一基准:只认窗口,抛弃屏幕

所有栅格、尺寸计算、坐标拾取全部基于BreakpointReference.WINDOW窗口可视区域。
分屏、拉伸、悬浮、平行视界只会改变窗口大小,设备物理屏幕尺寸不变,用屏幕断点必然失效。
全局固定一套断点阈值,全项目统一,杜绝各页面自定义阈值造成视觉割裂:

const BREAK_POINTS = ["320vp", "600vp", "840vp", "1200vp"];
const GRID_COLS = { xs:1, sm:2, md:3, lg:4 };

在这里插入图片描述
页面栅格统一模板,全项目复用:

GridRow({
  breakpoints: {
    value: BREAK_POINTS,
    reference: BreakpointReference.WINDOW
  },
  columns: GRID_COLS,
  gutter: { x:12, y:16 }
})

2. 全局单一状态源,全页面共享

在这里插入图片描述
只在应用入口初始化一次窗口、折叠状态监听,存入AppStorageV2全局观测变量,所有页面只读不监听,避免重复回调造成闪烁、卡顿。

@ObservedV2
export class WindowVM {
  @Trace winW: number = 0;
  @Trace bp: string = "xs";
  @Trace foldMode: number = 0; // 0合拢 1展开 2悬停
}

窗口尺寸、折叠形态变更统一更新这个全局对象,页面直接读取,无需重复注册windowSizeChange、折叠监听。

3. 形态渲染优先级固定死

全局统一判断顺序,不允许颠倒:悬停Hover > 展开大屏分屏 > 合拢窄屏单列
悬停状态强制单列上下分区,禁止渲染平行视界双栏,从根源避免分屏与悬停布局互相冲突错乱。

三、悬停布局最优解:FolderStack原生容器,告别手动避让

之前大量项目用Column+自定义padding适配悬停,不同设备折痕高度不同,适配效果参差不齐,交互按钮容易被遮挡、点击无响应。
鸿蒙7官方推荐FolderStack,原生支持自动跟随折痕,无需手动计算间距:

FolderStack() {
  // 上屏:预览展示区
  Column() { PreviewContent() }.layoutWeight(2)
  // 下屏:操作交互区,完全避开折痕
  Column() { ActionBar() }.layoutWeight(1)
}
.autoFollowFoldLine(true)
.width("100%")
.height("100%")

上下区域物理隔离,所有输入框、操作按钮全部下沉下屏,从根源杜绝折痕遮挡交互。

四、一套业务组件复用全形态,杜绝多套页面

核心原则:业务卡片、表单、按钮只写一套Builder,合拢、展开、悬停只是外层容器结构变化,内部业务逻辑完全复用。

  • 合拢窄屏:单列栅格列表;
  • 展开大屏:Row左右平行视界双栏;
  • 半折悬停:FolderStack上下分区;
    三种形态共用同一个商品/点检卡片,只改变外层布局容器,业务代码无重复。

动态布局示例

@ComponentV2
struct CheckPage {
  @Local winState: WindowVM = AppStorageV2.connect(WindowVM, "win_state", ()=>new WindowVM())!;
  @Local @Type(CheckItem) list: CheckItem[] = [];

  @Builder CheckCard(item: CheckItem) {
    // 通用业务卡片,三形态完全复用
  }

  build() {
    Column() {
      if (this.winState.foldMode === 2) {
        // 悬停上下分区
        FolderStack() {
          Column(){ Preview() }.layoutWeight(2)
          Column(){ GridRow(){ Repeat(this.list, i=>this.CheckCard(i), i=>i.id) } }.layoutWeight(1)
        }.autoFollowFoldLine(true)
      } else if (this.winState.bp === "md" || this.winState.bp === "lg") {
        // 展开双栏平行视界
        Row() {
          Column().layoutWeight(0.6) { GridRow(){ Repeat(this.list, i=>this.CheckCard(i), i=>i.id) } }
          Column().layoutWeight(0.4) { DetailForm() }
        }
      } else {
        // 合拢单列
        GridRow(){ Repeat(this.list, i=>this.CheckCard(i), i=>i.id) }
      }
    }
    .padding(16)
    .width("100%")
  }
}

五、配套优化,解决折叠切换闪烁、坐标漂移

  1. 列表统一使用Repeat + 业务唯一ID作为key
    彻底抛弃index作为key,折叠切换不会出现组件复用错乱、页面闪白。
  2. 弹窗增加尺寸约束
    自由分屏、窄窗口不会溢出屏幕:
CustomDialog() {
  // 弹窗内容
}.constraintSize({ maxWidth: "90%", maxHeight: "80%" })
  1. 交互坐标统一修正窗口偏移
    ShareKit碰一碰、点击拾取坐标,屏幕坐标减去窗口偏移得到相对坐标,搭配50px容错区域,平行视界、悬停不会匹配错位。
  2. 禁止硬编码固定宽高
    页面主体全部使用layoutWeight权重自适应,字体、间距根据断点动态计算,适配任意拉伸窗口。

六、Kiosk商用终端额外适配要点

折叠手势、分屏系统弹窗会绕过锁机逃逸业务界面,双层防护:

  1. MDM管控策略全局禁用分屏、折叠系统手势、悬浮窗;
  2. Agent后台监听折叠形态变更,布局异常自动重置并重上锁;
  3. 全局窗口固定fullScreen模式,禁止自由拉伸多窗口。

七、随笔小结

鸿蒙7这套基于窗口断点栅格+全局统一状态+FolderStack原生悬停容器的自适应方案,真正做到一码适配万物:手持合拢、展开大屏、操作台悬停、自由分屏、自助Kiosk、PC宽屏全部一套代码覆盖。
不再需要维护多套页面、大量尺寸判断、手动折痕适配,大幅减少折叠适配bug,降低迭代维护成本,同时兼顾低端工业触控机性能,形态切换流畅无闪烁,是商用折叠终端标准化开发最优路径。

Logo

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

更多推荐