HarmonyOS鸿蒙Next中ArkUI页面简化支持RC组件库开发指导

HarmonyOS鸿蒙Next中ArkUI页面简化支持RC组件库开发指导

概述

当前HarmonyOS应用开发的过程中,断点需要开发者自己定义布局边界,由于HarmonyOS设备种类众多,因此断点适配需要设计多种布局,给开发者带来不便。

考虑到部分应用的布局形态仅考虑小屏(如直板机)与大屏(如平板)两种状态,本文将介绍一种对窗口布局适配精细度要求较低,且对特定组件有独立布局要求的布局方案:

1、在应用窗口级别,定义横纵方向的布局分别为 R (Regular,宽松) /C (Compact,紧凑) 两种,即 2x2 的布局方案。

2、在应用容器级别,每个容器可定义独立于窗口级 RC 布局的容器级 RC 布局。

3、针对每种 RC 布局方案,配置相应的资源后可根据布局自动获取相应资源。

效果展示

注意:本文中的测试与效果演示设备为 Mate 60,系统版本为 5.0.0.123,使用其他设备可能由于设备大小或版本差异导致布局与文中效果不一致,需开发者根据实际情况进行调整。

横向紧凑,纵向不限 (Mate 60竖屏) 横向宽松,纵向不限 (Mate 60横屏)

原理介绍

监听回调

窗口级 RC 布局通过媒体查询的方式监听窗口大小,并根据大小变化的回调更新布局状态。由于媒体查询依赖 UI 上下文,因此需要保证监听注册处 UIContext 可获取,参见 UIContext 说明。

容器级 RC 目前通过绑定组件尺寸变化事件实现监听效果,在尺寸变化事件回调中更新布局状态。

横纵断点

窗口级 RC 布局本质上是一套简化的断点机制,将 HarmonyOS 4 * 3 的断点简化为 2 * 2 的规格。

窗口 RC 分界值
横向 可根据实际需求自行配置,范围:[0, 2560],默认 600,单位为 vp
纵向 可根据实际需求自行配置,范围:[0, 2560],默认 800,单位为 vp

资源获取

根据文件名以及 RC 布局状态匹配对应的目录并获取相应资源,需要开发者按需自行创建相应目录并配置资源。

依赖安装

通过 ohpm 下载并安装依赖,OpenHarmony ohpm 环境配置等更多内容,请参考 如何安装 OpenHarmony ohpm 包。

ohpm install @hadss/size_class_layout

使用说明

窗口级 RC 布局

适配说明

1、选择监听使用方式:

a. 在 EntryAbility.ets 中定义 SizeClassManager 对象,在窗口的初始化与销毁回调中分别设置窗口监听与解绑逻辑,此时需要注意监听注册处 UIContext 可获取。例如在 onWindowStageCreate 内调用 loadContent 或 getMainWindow,之后在其回调函数内注册监听,之后再 onWindowStageWillDestory 内进行解绑。

b. 在页面声明式 UI 内定义 SizeClassManager 对象,在 aboutToAppear 与 aboutToDisappear 中分别设置窗口监听与解绑逻辑。

2、在 UI 页面文件中,按需定义 @StorageLink 修饰的横纵向布局状态变量。

3、在上述变量定义的组件中,定义 SizeClassState 对象,使用不同状态下的配置值对其进行初始化,后续使用 getValue 方法根据当前状态获取配置值。

场景案例

默认布局(横向紧凑,纵向不限布局)下,文本所在 Column 组件缩放倍率为 1;横向宽松且纵向不限布局下,文本所在 Column 组件缩放倍率为 2。通过旋转设备切换窗口的布局状态,可以直接观察到文本大小的变化。

横向紧凑,纵向不限 (Mate 60) 横向宽松,纵向不限 (Mate 60)

关键代码片段:

// EntryAbility.ets
// 导入依赖对象 
import { SizeClassManager } from '@hadss/size_class_layout'; 

export default class EntryAbility extends UIAbility {
  private sizeClassManager: SizeClassManager | undefined = undefined;
  // ...
  onWindowStageCreate(windowStage: window.WindowStage): void {
    // ...
    windowStage.getMainWindow((err, windowClass) => {
      // 步骤一:定义窗口监听对象,默认横向布局边界为600vp,纵向为800vp。此处在getMainWindow回调函数内注册保证监听成功。
      this.sizeClassManager = new SizeClassManager();
      // 步骤一:注册窗口监听逻辑定义
      this.sizeClassManager.register();
    })
  }

  onWindowStageWillDestroy(): void {
    // 步骤一:解除窗口监听逻辑定义
    this.sizeClassManager?.unregister();
  }
}
// Index.ets
// 导入依赖对象 
import { SizeClassState, SizeClassType, Constants } from '@hadss/size_class_layout';
import { window } from '@kit.ArkUI';

@Entry
@Component
struct Index {
  // 步骤二:定义横向布局状态
  [@StorageLink](/user/StorageLink)(Constants.HORIZONTAL_PROPNAME) wSizeType: SizeClassType = SizeClassType.ANY;
  // 当前窗口宽度
  [@State](/user/State) windowWidth: number = 0;
  private windowStage: window.Window | undefined = undefined;

  async aboutToAppear(): Promise<void> {
    // 注册窗口宽度监听
    this.windowStage = await window.getLastWindow(getContext(this));
    this.windowStage.on('windowSizeChange', (windowSize: window.Size) => {
      this.windowWidth = px2vp(windowSize.width);
    });
    // 获取窗口宽度初始值
    this.windowWidth = px2vp(this.windowStage.getWindowProperties().windowRect.width);
  }

  aboutToDisappear(): void {
    // 取消监听
    this.windowStage?.off('windowSizeChange');
  }

  build() {
    Column() {
      Column() {
        Text(`Window widthSizeType: ${this.wSizeType}`)
        // 实时展示当前窗口宽度与布局边界值
        Text(`Window width: ${this.windowWidth.toFixed(0)}vp, horizontal border: ${Constants.DEFAULT_HORIZONTAL_BORDER}vp`)
      }
      // 步骤三:定义不同状态下的配置值并使用,根据窗口布局状态改变Column组件显示缩放倍率
      .scale(new SizeClassState<ScaleOptions>({
        // any为默认布局,处理无匹配布局状态的情况
        any: {
          x: 1,
          y: 1
        },
        wCAndHAny: {
          x: 1,
          y: 1
        },
        wRAndHAny: {
          x: 2,
          y: 2
        }
      }).getValue({widthSizeType: this.wSizeType}))
    }
    .justifyContent(FlexAlign.Center)
    .width('100%')
    .height('100%')
  }
}

容器级 RC 布局

适配说明

1、定义 SizeClassRule 对象,使用容器 RC 的布局边界进行初始化。

2、在 UI 页面文件中,按需定义 @State 修饰的横纵向布局状态变量。

3、在 RC 布局作用的容器对象中,在其 onSizeChange 方法中使用新的布局边界更新 SizeClassRule 内部的 RC 状态,并更新至上一步骤中定义的状态变量。

4、在自定义布局状态变量的作用范围内,定义 SizeClassState 对象,使用不同状态下的配置值对其进行初始化,后续使用 getValue 方法传入当前状态获取配置值。

场景案例

默认布局(横向紧凑,纵向宽松布局)下,Column 组件为黄色;横向宽松且纵向紧凑布局下,Column 组件为灰色。通过旋转设备切换 Column 容器的布局状态,可直接观察到颜色的变化。

横向紧凑,纵向宽松 (Mate 60) 横向宽松,纵向紧凑 (Mate 60)

关键代码片段:

// Index.ets
// 导入依赖对象 
import { SizeClassBorder, SizeClassRules, SizeClassState, SizeClassType } from '@hadss/size_class_layout';

// 定义横向边界为200vp,纵向边界为200vp
const rulesBorder: SizeClassBorder = {
  horizontalBorder: 200,
  verticalBorder: 200
}

@Entry
@Component
struct Index {
  // 步骤一:定义容器布局边界,使用上述布局进行初始化
  private containerRule: SizeClassRules = new SizeClassRules(rulesBorder);
  // 步骤二:定义容器横向布局状态
  [@State](/user/State) wSizeType: SizeClassType = SizeClassType.ANY;
  // 步骤二:定义容器纵向布局状态
  [@State](/user/State) hSizeType: SizeClassType = SizeClassType.ANY;
  [@State](/user/State) columnWidth: number = 0;
  [@State](/user/State) columnHeight: number = 0;

  build() {
    Column() {
      // 展示Column组件宽高度信息、布局边界值以及RC状态
      Text(`Column width: ${this.columnWidth.toFixed(0)}vp, border: ${rulesBorder.horizontalBorder}vp`)
      Text(`Column height: ${this.columnHeight.toFixed(0)}vp,, border: ${rulesBorder.verticalBorder}vp`)
      Text(`Column wSizeType: ${this.wSizeType}`)
      Text(`Column hSizeType: ${this.hSizeType}`)

      Column() {
      }
      .width('50%')
      .height('50%')
      // 步骤四:定义不同状态下的配置值并使用,根据Column组件布局状态改变其颜色
      .backgroundColor(new SizeClassState<Color>({
        // any为默认布局,处理无匹配布局状态的情况
        any: Color.Yellow,
        wCAndHR: Color.Yellow,
        wRAndHC: Color.Gray,
      }).getValue({ widthSizeType: this.wSizeType, heightSizeType: this.hSizeType }))
      .onSizeChange((oldValue: SizeOptions, newValue: SizeOptions) => {
        if (typeof newValue.width === 'number' && typeof newValue.height === 'number') {
          // 步骤三:根据容器变化后的布局边界更新RC状态
          this.containerRule.updateSizeClassType({ width: newValue.width ?? 0, height: newValue.height ?? 0 });
          // 步骤三:获取更新后的横向容器RC状态
          this.wSizeType = this.containerRule.getHorizontalSizeClass();
          this.hSizeType = this.containerRule.getVerticalSizeClass();
          // 更新Column组件宽高度
          this.columnWidth = newValue.width;
          this.columnHeight = newValue.height;
        }
      })
    }
    .justifyContent(FlexAlign.Center)
    .width('100%')
    .height('100%')
  }
}

RC 资源适配

适配说明

1、在 resources 下新建 rawfile/size_media,内部可配置相应布局下的资源。

2、在 EntryAbility 或 UI 页面文件内应用窗口级 RC 或者容器级 RC。

3、在 UI 页面文件内,根据上一步骤中选择的 RC 类型定义相应的横纵向布局状态变量。

4、在上述布局状态变量的作用范围内,调用 SizeClassResUtils 的静态 getRes 方法,通过传入资源名与布局状态来获取相应资源。

场景案例

下图样例使用默认布局边界值(横向 600vp,纵向 800vp)。在横向紧凑布局下,为默认图片资源;横向宽松布局下,图片资源发生变化。通过旋转设备切换窗口的布局状态,可以直接观察到图片的变化。

横向紧凑,纵向不限 (Mate 60) 横向宽松,纵向不限 (Mate 60)

关键代码片段:

// 步骤一:创建资源文件夹,创建后的工程目录结构如下
/*
 * └── entry                                            // 工程入口文件夹 
 *     └── src 
 *         └── main 
 *             └── resources 
 *                 ├── rawfile                           // rawfile文件夹,需要创建 
 *                 │   └── size_media                    // size_media文件夹,需要创建 
 *                 │       ├── base                      // 通用布局,在未匹配到相应布局时适用,此处配置以避免特定布局资源访问异常 
 *                 │       │   └── shopHeaderImage.png   // 对应布局下的资源 
 *                 │       ├── ca                        // 横向紧凑,纵向不限(wCAndHAny) 
 *                 │       │   └── shopHeaderImage.png   // 对应布局下的资源 
 *                 │       └── ra                        // 横向宽松,纵向不限(wRAndHAny) 
 *                 │           └── shopHeaderImage.png   // 对应布局下的资源 
 *                 ├── base                              // 默认base资源文件夹 
 *                 ├── en_US                             // 默认en_US资源文件夹 
 *                 └── zh_CN                             // 默认zh_CN资源文件夹 
 */
// EntryAbility.ets 
// 步骤二:应用窗口级RC,代码与窗口级RC布局一致,此处省略
// Index.ets 
// 导入依赖对象 
import { SizeClassType, SizeClassResUtils, Constants } from '@hadss/size_class_layout'; 
import { window } from '@kit.ArkUI'; 

@Entry
@Component
struct Index {
  // 步骤三:定义横向布局状态 
  [@StorageLink](/user/StorageLink)(Constants.HORIZONTAL_PROPNAME) wSizeType: SizeClassType = SizeClassType.ANY; 
  // 当前窗口宽度 
  [@State](/user/State) windowWidth: number = 0; 
  private windowStage: window.Window | undefined = undefined; 

  async aboutToAppear(): Promise<void> { 
    // 注册窗口宽度监听 
    this.windowStage = await window.getLastWindow(getContext(this)); 
    this.windowStage.on('windowSizeChange', (windowSize: window.Size) => { 
      this.windowWidth = px2vp(windowSize.width); 
    }); 
    // 获取窗口宽度初始值 
    this.windowWidth = px2vp(this.windowStage.getWindowProperties().windowRect.width); 
  } 

  aboutToDisappear(): void { 
    // 取消监听 
    this.windowStage?.off('windowSizeChange'); 
  } 

  build() {
    Column() {
      Column() {
        Text(`Window widthSizeType: ${this.wSizeType}`)
          .backgroundColor(Color.Yellow)
        // 步骤四:根据图片名以及横向布局状态获取相应图片资源 
        Image(SizeClassResUtils.getRes('shopHeaderImage.png', { widthSizeType: this.wSizeType }))
          .width('80%')
          .height('80%')
        // 实时展示当前窗口宽度与布局边界值 
        Text(`Window width: ${this.windowWidth.toFixed(0)}vp, horizontal border: ${Constants.DEFAULT_HORIZONTAL_BORDER}vp`)
          .backgroundColor(Color.Yellow)
      }
    }
    .justifyContent(FlexAlign.Center)
    .width('100%')
    .height('100%')
  }
}

注意事项

1、在 EntryAbility 中注册监听时,建议在 onWindowStageCreate 内调用 loadContent 或 getMainWindow,之后在其回调函数内注册监听,保证注册监听处媒体查询生效。可参考本文的“原理介绍”一节。

2、建议在 onWindowStageWillDestory/onWindowStageDestory 方法调用 unregister 取消窗口监听,避免内存泄漏。

3、当应用对某一方向布局不敏感时,可以只定义单一布局状态进一步减少复杂度,常见于直板机/横向折叠/平板间的布局适配,一般仅需考虑横向状态,此时纵向布局状态默认为 ANY。

4、使用布局配置时,如果已定义的布局类型覆盖不全面,可能存在未匹配到部分布局的情况,例如仅定义了 cr 与 rc 的布局,导致 rr 无法匹配,使用出现异常。这种情况建议额外配置通用布局,即使用 SizeClassState 时定义 any 下的配置,使用 SizeClassResUtils 前配置 base 目录下的资源。

示例代码

基于 ArkUI 页面简化支持 RC 组件库开发 sample 示例


更多关于HarmonyOS鸿蒙Next中ArkUI页面简化支持RC组件库开发指导的实战教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

HarmonyOS鸿蒙Next中,ArkUI页面简化支持RC组件库开发,主要通过预置的组件和模板来提升开发效率。RC组件库提供了丰富的UI组件,如按钮、列表、卡片等,开发者可直接调用,减少代码量。ArkUI框架支持声明式UI开发,通过简洁的DSL描述界面布局和逻辑,简化了页面开发流程。RC组件库与ArkUI深度集成,支持响应式布局和状态管理,确保界面在不同设备上自适应。开发者可通过DevEco Studio快速创建和调试基于RC组件库的页面。

更多关于HarmonyOS鸿蒙Next中ArkUI页面简化支持RC组件库开发指导的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


HarmonyOS Next的RC组件库开发确实为多设备适配提供了简化方案。关于您提到的ArkUI页面简化适配,以下是关键点说明:

RC布局原理:

  • 采用2x2简化断点机制(Regular/Compact)
  • 通过媒体查询监听窗口变化
  • 支持窗口级和容器级双重布局控制

实际开发建议:

  • 资源目录需按规范创建(如rawfile/size_media)
  • 推荐在EntryAbility的loadContent回调中注册监听
  • 务必在onWindowStageWillDestroy中取消监听

典型应用场景:

  • 横竖屏切换时自动调整布局
  • 不同设备尺寸下的差异化显示
  • 组件级别的响应式设计

示例代码中展示的状态管理(@StorageLink)和资源获取(SizeClassResUtils)方式值得参考。需要注意边界值配置应根据实际项目需求调整,默认值(横向600vp/纵向800vp)可能不适合所有场景。

这种方案相比传统媒体查询确实减少了适配工作量,特别适合只需要区分大屏/小屏的场景。

回到顶部