Harmony OS 界面适配全攻略(一多开发)

0 阅读8分钟

 一、引言

在 HarmonyOS 应用开发的广阔天地里,“一多开发” 宛如一座桥梁,搭建起一次开发、多端部署的高效之路。今天,咱们就聚焦在 “一多开发” 的核心概念,尤其是界面级的适配技巧,看看如何让应用在不同屏幕尺寸的设备上都能展现出完美的视觉效果。

二、“一多开发” 核心概念(1 + 8 + N 模式)

(一)目标

HarmonyOS “一多开发” 的目标非常明确,就是实现一次开发多端部署,让开发者能够更高效地覆盖多种设备,提升开发效率,降低开发成本。

(二)解决的问题

  1. 界面级一多:不同设备屏幕尺寸千差万别,如何让应用界面在各种屏幕上都能布局合理、美观大方,这就需要解决界面适配不同屏幕尺寸的问题。
  2. 功能级一多:各类设备的功能特性不尽相同,像有些设备可能具备特定的传感器,而有些没有。这就要求我们在开发时处理好设备功能兼容性,通过 “CanIUser” 机制确保应用在不同设备上功能正常运行。
  3. 工程级一多:项目架构管理也是一大挑战,采用三成架构 HAP(HarmonyOS Application Package)、HAR(HarmonyOS Archive)、HSP(HarmonyOS Solution Package),让项目结构清晰,便于开发、维护和管理。

三、界面级一多解决方法

(一)自适应布局

自适应布局就像是一个聪明的裁缝,能够根据不同的屏幕尺寸,灵活地调整衣服的版型。它有许多实用的能力,通过核心属性和组件来实现。

  1. 拉伸:使用 flexGrowflexShrink 属性,就像给组件赋予了弹性。比如 .flexGrow(1).flexShrink(1),这样组件就能在空间充足时伸展,空间不足时收缩。
  2. 均分justifyContent: SpaceEvenly 可以让子组件在容器中均匀分布。就像一排小朋友手拉手,每个人之间的距离都一样。代码实现为 Row().justifyContent(FlexAlign.SpaceEvenly)
  3. 占比:通过 layoutWeight 或者百分比宽高来确定组件的占比。比如 .width('50%').layoutWeight(1),这就像分蛋糕,按比例分配空间。
  4. 缩放aspectRatio 属性可以保持组件的宽高比。就像看电影时,屏幕的宽高比不变,画面才不会变形。使用方式为 .aspectRatio(1.5)
  5. 延伸ListScroll 结合 Row 可以实现横向滚动展示。就像超市的货架,东西太多一行放不下,就可以滚动查看。代码是 List().listDirection(Axis.Horizontal)
  6. 隐藏displayPriority 属性可以控制组件的显示优先级。数值越大,优先级越低,可能就会被隐藏。例如 .displayPriority(2)
  7. 折行FlexWrap.Wrap 可以让组件在一行排不下时自动换行。就像排队的人太多,就分成几排。代码为 Flex({ wrap: FlexWrap.Wrap })

(二)响应式布局

响应式布局就像一个智能的魔法师,能够根据不同的设备屏幕尺寸,变出最合适的界面。它主要通过以下几种方式实现。

1、断点系统:为不同尺寸范围的屏幕设定断点,每个断点对应不同类型的设备。

  • xs:范围在 [0, 320) vp,典型设备是智能手表。
  • sm:范围在 [320, 600) vp,常见于手机竖屏。
  • md:范围在 [600, 840) vp,适用于折叠屏或横屏设备。
  • lg:范围在 [840, +∞) vp,平板或 PC 属于此类。

在 Ability 中,可以通过监听窗口变化来判断当前的断点。例如:

windowObj.on('windowSizeChange', (size) => {
  const widthVp = size.width / density;
  AppStorage.set('currentBreakpoint', calculateBreakpoint(widthVp));
});

2、媒体查询:这就像是给应用装上了一双 “慧眼”,能够识别不同的屏幕条件。

// 创建监听器
const listener = mediaquery.matchMediaSync('(320vp<=width<600vp)');
// 注册回调
listener.on('change', (res) => {
  if (res.matches) AppStorage.set('breakpoint','sm');
});
// 移除监听
listener.off('change');

3、栅格布局:栅格布局就像搭建积木,通过定义行和列的规则,快速搭建出复杂的布局。

//GridRow:定义行布局规则
GridRow({
  columns: { sm: 4, md: 8, lg: 12 },
  gutter: 10
})
//GridCol:定义列占比与偏移
GridCol({
  span: { sm: 2, md: 4 },
  offset: { md: 1 }
})

(三)不同场景下的推荐方案

  1. 微调元素尺寸:推荐使用自适应布局中的占比或拉伸方式。这种方式简单高效,就像给组件轻轻地 “拉扯” 一下,代码侵入性低,能快速实现元素尺寸的微调。
  2. 多设备显隐逻辑:响应式布局中的媒体查询是个好帮手。它可以像一个精准的探测器,精确控制不同断点下的 UI 表现,让组件在合适的设备上显示或隐藏。
  3. 复杂多列布局:栅格系统是不二之选。它内置了响应规则,就像有一套预设好的布局模板,维护性强,轻松应对复杂多列布局。
  4. 全局断点状态管理:使用 BreakpointSystem 工具,它就像一个指挥官,统一管理断点,避免重复监听,让整个应用的断点管理井井有条。

(四)界面级一多断点实现代码解析

下面这段代码基于鸿蒙特定 API,实现了窗口尺寸监听与断点计算更新。

import window from '@ohos.window'
import display from '@ohos.display'
import UIAbility from '@ohos.app.ability.UIAbility'

export default class EntryAbility extends UIAbility {
  private windowObj?: window.Window
  private curBp: string = ''
  //...
  // 根据当前窗口尺寸更新断点
  private updateBreakpoint(windowWidth: number) :void{
    // 将长度的单位由px换算为vp
    let windowWidthVp = windowWidth / display.getDefaultDisplaySync().densityPixels
    let newBp: string = ''
    if (windowWidthVp < 320) {
      newBp = 'xs' // 超小屏
    } else if (windowWidthVp < 600) {
      newBp ='sm' // 小屏
    } else if (windowWidthVp < 840) {
      newBp ='md' // 中屏
    } else {
      newBp = 'lg' // 大屏
    }
    if (this.curBp!== newBp) {
      this.curBp = newBp
      // 使用状态变量记录当前断点值
      AppStorage.setOrCreate('currentBreakpoint', this.curBp)
    }
  }

  onWindowStageCreate(windowStage: window.WindowStage) :void{
    windowStage.getMainWindow().then((windowObj) => {
      this.windowObj = windowObj
      // 获取应用启动时的窗口尺寸
      this.updateBreakpoint(windowObj.getWindowProperties().windowRect.width)
      // 注册回调函数,监听窗口尺寸变化
      windowObj.on('windowSizeChange', (windowSize)=>{
        this.updateBreakpoint(windowSize.width)
      })
    });
   //...
  }
   
  //...
}

  1. 鸿蒙特定 API:代码基于 @ohos.window@ohos.display@ohos.app.ability.UIAbility 模块开发。这些模块是 HarmonyOS 提供的原生 API,就像给开发者配备了一套专属的工具包,能够方便地进行窗口管理、显示信息获取以及应用能力相关操作。
  2. 窗口尺寸监听:在 onWindowStageCreate 方法中,通过 windowStage.getMainWindow().then 获取主窗口对象,就像找到了应用界面的 “舞台”。然后利用 windowObj.on('windowSizeChange',...) 注册回调函数,实时监听窗口尺寸变化,这是整个屏幕适配的起点,为后续的操作提供基础数据。
  3. 断点计算与更新updateBreakpoint 方法把获取到的窗口宽度从像素(px)换算为虚拟像素(vp),就像把不同单位的长度统一起来。再根据不同的 vp 范围确定对应的断点值(xs、sm、md、lg)。当计算出的新断点与当前断点不同时,更新当前断点,并通过 AppStorage.setOrCreate 方法记录在状态变量中。这一步就像给应用设置了一个 “标记”,告诉应用当前处于哪个屏幕尺寸范围,以便应用的其他部分根据这个 “标记” 进行不同的布局或功能调整。

四、总结

本文深入探讨了 HarmonyOS “一多开发” 中的界面级适配问题。“一多开发” 的理念旨在解决应用在不同层面的适配与管理难题,为开发者提供高效的开发模式。

在界面级,自适应布局和响应式布局是实现屏幕适配的两大法宝。自适应布局简单直接,能快速调整元素尺寸;响应式布局则更加智能精准,满足各种复杂的界面需求。

结合鸿蒙特定 API 的代码示例,我们详细了解了窗口尺寸监听与断点计算更新的实现过程,这是界面适配的核心技术点。通过这些方法,开发者能够让应用在不同屏幕尺寸的设备上都呈现出完美的用户体验。希望大家在 HarmonyOS 应用开发的道路上,运用这些技巧,打造出更加出色的应用!

五、避坑指南:

  1. 自适应布局

    • 使用 flexGrowflexShrink 时,注意值的设置,过大或过小可能导致布局异常。比如设置 flexGrow 过大,可能会使某些组件占据过多空间。
    • layoutWeight 和百分比宽高一起使用时,要小心冲突。确保两种方式不会互相干扰,导致布局错乱。
  2. 响应式布局

    • 断点范围的划分要根据实际设备情况进行调整。如果划分不合理,可能导致某些设备的界面显示不符合预期。
    • 媒体查询的条件要写准确,否则可能出现误判,导致组件显示或隐藏错误。
  3. 代码实现

    • 在使用鸿蒙特定 API 时,注意版本兼容性。不同版本的 API 可能有不同的使用方法或参数,务必查看官方文档确认。
    • 状态变量的管理要清晰,避免在多个地方同时修改导致数据混乱,影响断点判断和布局调整。