【OpenHarmony/HarmonyOs 】响应式布局适配手机、平板与折叠屏:ResponsiveUtils 实战

HarmonyOS 应用经常需要面对多种设备:手机、平板、折叠屏,甚至更大的屏幕。学习类 App 尤其适合多端使用:手机刷题,平板看报纸,折叠屏一边看知识点一边答题。本文结合 政治视界 项目的 ResponsiveUtils.ets,详细讲解 ArkTS 中如何做响应式布局 📱

一、为什么不能只按手机设计

如果把手机页面直接拉伸到平板,会出现几个问题:

  • 卡片过宽,阅读不舒服;
  • 内容密度太低;
  • 页面留白过多;
  • 筛选栏和列表无法充分利用横向空间;
  • 折叠屏展开后体验像放大的手机。

所以项目中单独封装了响应式工具类,统一判断屏幕宽度、断点、布局模式。

二、设备和断点定义

ResponsiveUtils.ets 中定义了设备类型和断点:

export enum ScreenBreakpoint {
  SM = 'sm',
  MD = 'md',
  LG = 'lg',
  XL = 'xl'
}

export enum LayoutMode {
  COMPACT = 'compact',
  REGULAR = 'regular',
  EXPANDED = 'expanded'
}

断点用于判断屏幕大小,布局模式用于决定页面怎么排版:

  • COMPACT:手机竖屏,单列;
  • REGULAR:横屏或小平板,适度增加内容宽度;
  • EXPANDED:大平板或折叠屏展开,适合双列。

三、初始化屏幕信息

工具类初始化时读取屏幕信息:

private async initScreenInfo(): Promise<void> {
  const displayInfo = await display.getDefaultDisplaySync();
  this.screenWidth = px2vp(displayInfo.width);
  this.screenHeight = px2vp(displayInfo.height);
  this.screenDensity = displayInfo.densityDPI / 160;
  this.isLandscape = this.screenWidth > this.screenHeight;

  this.updateBreakpoint();
  this.updateDeviceType();
  this.updateLayoutMode();
  this.setupFoldListener();
}

这里把像素转成 vp,是因为 ArkUI 布局更适合用 vp 做适配。

四、布局模式判断

核心判断逻辑如下:

private updateLayoutMode(): void {
  if (this.isFoldable && this.foldState === 2) {
    this.layoutMode = LayoutMode.EXPANDED;
  } else if (this.screenWidth >= 840) {
    this.layoutMode = LayoutMode.EXPANDED;
  } else if (this.screenWidth >= 600 || this.isLandscape) {
    this.layoutMode = LayoutMode.REGULAR;
  } else {
    this.layoutMode = LayoutMode.COMPACT;
  }
}

这段代码体现了一个思路:不要只判断设备名称,而要判断可用空间。折叠屏展开后,即使仍是移动设备,也应该使用大屏布局。

五、页面中使用响应式参数

各页面都维护类似状态:

@State private responsiveInfo: ResponsiveInfo = responsive.getResponsiveInfo();
@State private isTwoColumn: boolean = false;
@State private contentPadding: number = 16;
@State private cardRadius: number = 20;
@State private titleFontSize: number = 24;

页面出现时更新参数:

private updateResponsiveParams(): void {
  this.isTwoColumn = responsive.shouldShowTwoColumn();
  this.contentPadding = responsive.getHorizontalPadding();
  this.cardRadius = responsive.getBorderRadius('lg');
  this.titleFontSize = responsive.getFontSize('xl') + 4;
}

这样页面里的 padding、圆角、字号、布局列数都能跟随设备变化。

六、监听屏幕变化

页面注册监听器:

aboutToAppear(): void {
  this.updateResponsiveParams();
  responsive.addListener(this.onResponsiveChange);
}

aboutToDisappear(): void {
  responsive.removeListener(this.onResponsiveChange);
}

private onResponsiveChange = (info: ResponsiveInfo): void => {
  this.responsiveInfo = info;
  this.updateResponsiveParams();
}

注意 aboutToDisappear() 中移除监听,否则页面销毁后仍可能收到回调,造成不必要的问题。

七、哪些页面适合双列

在政治视界中,双列布局特别适合:

  • 首页:左侧学习统计,右侧推荐题和错题;
  • 笔记:左侧笔记列表,右侧详情;
  • 报纸:左侧文章列表,右侧文章内容;
  • 闪卡:左侧筛选,右侧卡片;
  • 学习报告:左侧概览,右侧分类统计。

手机上单列更适合快速操作,平板上双列更适合阅读和对比。

八、实现流程总结

定义断点和布局模式
  ↓
读取屏幕宽高与密度
  ↓
判断横竖屏和折叠状态
  ↓
根据宽度得到 COMPACT/REGULAR/EXPANDED
  ↓
页面订阅响应式变化
  ↓
更新 padding、字号、圆角、列数

九、实践建议

写响应式布局时,不建议每个页面都自己判断屏幕宽度。统一封装工具类更好:

  • 阈值统一;
  • 页面代码更干净;
  • 后续调整断点只改一处;
  • 折叠屏和横屏逻辑更容易复用。

十、结语

响应式布局不是简单适配屏幕,而是为不同设备重新组织信息。政治视界通过 ResponsiveUtils 把设备判断、断点、折叠屏状态和尺寸参数集中管理,让页面可以自然适配手机、平板和折叠屏。

HarmonyOS 的全场景能力给了学习 App 很大空间。做好响应式,就是迈向全场景学习体验的第一步 🚀

img

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐