如今鸿蒙生态里的设备千奇百怪,除了直板手机,还有折叠屏(展开/折叠)、平板、甚至 PC。很多应用在手机上跑得好好的,一到折叠屏展开态,要么左右拉伸得没法看,要么内容挤成一团;要是用户再开个分屏,整个页面直接面目全非。如果你的代码里还写着 if (deviceType === 'phone'),那说明你还没摸到鸿蒙多端适配的精髓。记住一个铁律:只认窗口宽度,不认设备型号。

用onAreaChange实时感知窗口尺寸

为什么不能用设备型号?因为折叠屏合拢时就是手机,展开时就是平板,分屏时甚至可能只有 300vp 的宽度。你拿设备型号判断,在分屏场景下直接歇菜。

正确的做法是监听组件区域或窗口的尺寸变化。在 ArkUI 中,我们可以通过 .onAreaChange 实时获取当前容器或页面的宽度。

typescript

@Entry
@ComponentV2
struct AdaptivePage {
  @Local windowWidth: number = 360; // 默认手机宽度

  build() {
    Column() {
      // 根据实时宽度切换布局
      if (this.windowWidth < 600) {
        this.SingleColumn()
      } else if (this.windowWidth < 840) {
        this.MediumLayout()
      } else {
        this.DualColumn()
      }
    }
    .width('100%')
    .height('100%')
    .onAreaChange((oldValue: Area, newValue: Area) => {
      // 宽度变化时,赋值触发精准刷新
      this.windowWidth = Number(newValue.width);
    })
  }

  @Builder
  SingleColumn() { /* 手机单列 */ }
  
  @Builder
  MediumLayout() { /* 折叠屏半展开 */ }
  
  @Builder
  DualColumn() { /* 平板/PC双列 */ }
}

这段代码的核心在于 .onAreaChange,只要用户的设备发生折叠、分屏拖拽或旋转,windowWidth 就会被更新,从而触发页面重新渲染。执行结果就是页面仿佛有了弹性,随窗口尺寸自由伸缩。

常见错误是把判断写在 aboutToAppear 里只执行一次。用户把折叠屏一折,你的布局就死在了平板模式,怎么划都别扭。

GridRow栅格化流转与陷阱

如果是复杂的卡片瀑布流或者排版,用 GridRow 配合 GridCol 是最高效的。它自带断点系统,你可以直接告诉它:在 sm(小屏)下占满 12 列,在 md(中屏)下占 8 列,在 lg(大屏)下占 4 列。

typescript

GridRow({
  columns: { sm: 4, md: 8, lg: 12 },
  gutter: { x: 16, y: 16 },
  breakpoints: { 
    value: ['600vp', '840vp'], 
    reference: BreakpointsReference.WindowSize 
  }
}) {
  ForEach(this.itemList, (item: any) => {
    GridCol({ 
      span: { sm: 4, md: 4, lg: 3 } // 大屏下一行放四个,中屏放两个,小屏放一个
    }) {
      this.ItemCard(item)
    }
  })
}

breakpoints 里的 reference 非常关键,一定要设成 WindowSize,这样栅格就会跟着窗口宽度走。执行结果就是无论你怎么折腾窗口,卡片都能整齐排列。

这里最大的坑是“无脑嵌套”。很多开发者为了微调 UI,在 GridCol 里面再套一个 GridRow,里面又套 Column。GridRow 的测量机制非常吃性能,嵌套超过两层,滑动的帧率直接崩盘。把内部的复杂 UI 抽离成自定义组件,让 GridCol 里面干干净净,这才是专业做法。

折叠屏折痕的避让策略

折叠屏不仅宽窄会变,中间还有一道折痕(铰链区)。如果在折叠状态下,你的重要按钮正好压在折痕上,用户根本点不到。鸿蒙在 API 11 之后提供了相关的容器组件来避让铰链区,比如 FoldSplitContainer。

如果你自己做自适应,可以通过系统窗口 API 获取当前的不可用区域(避让区),动态调整内边距。不要在代码里写死什么“左边偏移 100px”,不同型号的折叠屏,折痕宽度都不一样。适配的本质是顺应容器的变化,而不是跟它对着干。通过断点和栅格把内容“流”向可用空间,你的应用才能真正做到一次开发,多端部署。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐