HarmonyOS 7 实战开发 04:适配手机、折叠屏与大屏布局

前面几篇都是在折叠屏上开发的,布局看着挺好。但扔到手机上一跑,问题就来了------三栏布局在手机竖屏下挤成一团,文字小得看不清,左右边距也不对。这篇专门讲多设备适配,也是鸿蒙开发里和 Android 很不一样的地方。

HarmonyOS 7 的设备形态比 Android 更丰富:手机、折叠屏、平板、智慧屏,同一个应用要跑在这么多设备上,不能每台设备都写一套代码。官方提供了响应式布局的能力,用对了能省很多事。

设计思路:不要写死宽度

最开始我们直接把折叠屏上的布局搬到手机上,结果就是:左侧导航 200vp,右侧详情 360vp,中间内容区在手机上只剩下 100vp 左右,根本没法看。

正确的思路是:不要写死具体宽度,而是根据窗口大小动态调整布局。鸿蒙提供了几种方式:媒体查询、断点、自适应组件。

我们项目里主要用了断点的方式。把屏幕尺寸分成三档:小屏(<600vp)中屏(600-840vp)大屏(>840vp)。不同断点下布局不一样。

断点适配的实际实现

ArkUI 没有内置的断点 API,需要自己监听窗口尺寸变化。下面是我们封装的断点工具类,文件位置在 utils/BreakpointSystem.ets

typescript 复制代码
// 断点类型
export enum BreakpointType {
  SM = 'sm',  // 小屏:手机竖屏
  MD = 'md',  // 中屏:折叠屏展开、平板竖屏
  LG = 'lg'   // 大屏:折叠屏平板横屏、智慧屏
}

@Entry
@Component
struct WorkbenchPage {
  @State currentBreakpoint: BreakpointType = BreakpointType.SM;
  private windowStage: window.WindowStage | null = null;

  async aboutToAppear() {
    // 获取窗口对象,监听尺寸变化
    this.windowStage = await window.getLastWindow(this.context);
    this.updateBreakpoint(this.windowStage.getWindowProperties().windowRect.width);

    // 注册窗口尺寸变化监听
    this.windowStage.on('windowSizeChange', (size: window.Size) => {
      this.updateBreakpoint(size.width);
    });
  }

  private updateBreakpoint(width: number) {
    // 按宽度判断断点
    if (width < 600) {
      this.currentBreakpoint = BreakpointType.SM;
    } else if (width < 840) {
      this.currentBreakpoint = BreakpointType.MD;
    } else {
      this.currentBreakpoint = BreakpointType.LG;
    }
  }

  build() {
    // 根据断点决定布局方式
    if (this.currentBreakpoint === BreakpointType.LG) {
      // 大屏:三栏布局
      this.threeColumnLayout()
    } else if (this.currentBreakpoint === BreakpointType.MD) {
      // 中屏:两栏布局(隐藏右侧详情,用弹窗或跳转)
      this.twoColumnLayout()
    } else {
      // 小屏:单栏布局(Tab 切换或导航抽屉)
      this.singleColumnLayout()
    }
  }

  // 大屏三栏布局
  @Builder
  threeColumnLayout() {
    Row() {
      NavSideBar().width(200)
      ContentList().layoutWeight(1)
      DetailPanel().width(360)
    }
    .width('100%')
    .height('100%')
  }

  // 中屏两栏布局
  @Builder
  twoColumnLayout() {
    Row() {
      NavSideBar().width(160)
      ContentList().layoutWeight(1)
      // 详情面板:点击 item 时从右侧弹出
    }
    .width('100%')
    .height('100%')
  }

  // 小屏单栏布局
  @Builder
  singleColumnLayout() {
    Column() {
      // 顶部导航栏
      TopNavBar()
      // 内容列表
      ContentList().layoutWeight(1)
    }
    .width('100%')
    .height('100%')
  }
}

这个方案的好处:同一个页面,根据屏幕宽度自动切换布局。折叠屏展开的时候是三栏,合上变成手机就是单栏,不需要写多个页面。

组件内部的自适应

除了页面级别的布局切换,组件内部也要做适配。比如内容卡片,在大屏上可以显示更多信息,在小屏上就精简一下。

这里用了 @Builder 和条件渲染。还是那个 ContentCard 组件,根据断点调整显示的内容:

typescript 复制代码
@Component
struct ContentCard {
  @ObjectLink item: ContentItem;
  @Prop breakpoint: BreakpointType;

  build() {
    Row({ space: 12 }) {
      // 小屏:不显示封面图
      if (this.breakpoint !== BreakpointType.SM) {
        Image(this.item.coverUrl)
          .width(80)
          .height(80)
          .borderRadius(8)
      }

      Column({ space: 6 }) {
        Text(this.item.title)
          .fontSize(this.breakpoint === BreakpointType.LG ? 16 : 15)

        // 小屏:只显示一行摘要
        Text(this.item.summary)
          .fontSize(13)
          .maxLines(this.breakpoint === BreakpointType.SM ? 1 : 2)
          .textOverflow({ overflow: TextOverflow.Ellipsis })

        // 大屏:显示标签;小屏:隐藏标签
        if (this.breakpoint !== BreakpointType.SM) {
          Row({ space: 8 }) {
            ForEach(this.item.tags, (tag: string) => {
              Text(tag).fontSize(11)
            }, (tag: string) => tag)
          }
        }
      }
      .layoutWeight(1)
    }
    .width('100%')
    .padding(12)
  }
}

组件内部根据断点调整字号、显示行数、隐藏不必要的元素。这样一套组件,在不同尺寸下都能有合理的显示效果。

折叠屏的特殊处理

折叠屏比普通多了一个状态:折叠和展开。开合的时候窗口尺寸变化很大,上面的断点方案已经能处理了------展开的时候是 LG,合上变成 SM,自动切换布局。

但有个细节:开合的过程中要保持当前的选中状态。比如展开时选了第 5 篇文章,合上之后不能丢失这个选中态。我们的状态都在顶层 WorkbenchPage 里管理,窗口尺寸变化只是切换了布局,状态本身不变,所以这个问题自然就解决了。

还有一个容易忽略的点:折叠屏的分屏模式。如果应用在分屏下运行,窗口宽度可能正好在断点边界上。我们的断点是动态计算的,每次窗口尺寸变化都重新判断,所以分屏下也能正常工作。

横竖屏切换

工作台类应用一般锁定横屏,但如果要支持竖屏,也要注意适配。竖屏下宽度变窄,自动落到 SM 断点,切换成单栏布局。

横竖屏切换的时候,系统会重新创建页面,状态会丢失。如果要保留状态,可以用 AppStorage 或者 Preferences 把关键状态存下来,页面重建的时候再读回来。

适配调试技巧

DevEco Studio 的模拟器可以模拟不同设备:手机、折叠屏、平板、智慧屏。调试的时候多切换几种设备看效果。

还有个小技巧:打开布局边界(Show Layout Bounds),能看到每个组件的实际大小和边距,方便调整布局间距。

我们当时适配的时候,把所有页面都在折叠屏模拟器上打开开合好几次,确认布局切换没有闪烁、状态没有丢失,才算完成。

小结

多设备适配的核心就是:不要写死尺寸,用断点动态切换布局。HarmonyOS 7 的响应式能力已经很完善了,只要设计思路对,一套代码跑多设备不是难事。最后一篇讲工程收尾,怎么把页面做到可上线状态。

相关推荐
终端安全笔记1 小时前
iOS 27 强制 TLS 1.2:租赁设备的注册链路会在哪一环断
android·网络·安全·ios·智能手机
衝鋒壹号1 小时前
鸿蒙 PC 能跑 Docker 吗?一次从安装失败到成功运行的实测记录
后端·harmonyos
Latte Moments开发1 小时前
Harmony鸿蒙实战开发-浏览器app【源码在文末】
华为·harmonyos
黑科技iOS上架2 小时前
iOS深度混淆flutter应用的最佳实践
flutter·ios·混淆·审核·深度混淆
柒儿吖2 小时前
SSCom 重构全记录:用 Rust 把串口调试助手送上鸿蒙 PC、macOS、Windows和Linux
测试工具·rust·harmonyos
李游Leo2 小时前
HarmonyOS 7 端侧 AI 视觉能力实战 06:把识别、增强与搜索串成完整处理链
harmonyos
大雷神2 小时前
【共创稿事节】ArkGraphics 3D开发环境安装实战:从官网下载编辑器,到 DevEco Studio 离线装插件
harmonyos
李游Leo2 小时前
HarmonyOS 7 实战开发 02:用状态驱动复杂页面交互
harmonyos
大雷神2 小时前
【共创稿事节】HarmonyOS ArkGraphics 3D 实操——给智能音箱做一台结构探索台
harmonyos