本文同步发表于 微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新

HarmonyOS 支持深浅色两种显示模式。为提升用户体验,应用应适配深浅色模式。适配分为两种情况:

  1. 应用跟随系统的深浅色模式:应用随系统自动切换。

  2. 应用主动设置深浅色模式:应用固定为某种模式,不随系统变化。

二、应用跟随系统的深浅色模式

2.1 颜色适配

2.1.1 自定义资源实现
  • 在 resources 目录下创建深色模式限定词目录 dark,并在其中创建 color.json 文件,定义深色模式颜色

  • 在 base/element/color.json 中定义浅色颜色,在 dark/element/color.json 中定义深色颜色

示例:

// base/element/color.json
{
  "color": [
    {
      "name": "app_title_color",
      "value": "#000000"
    }
  ]
}
// dark/element/color.json
{
  "color": [
    {
      "name": "app_title_color",
      "value": "#FFFFFF"
    }
  ]
}
2.1.2 通过系统资源实现
  • 使用系统预置资源(分层参数),如 $r('sys.color.ohos_id_color_text_primary')

  • 系统自动根据深浅色模式切换颜色值,无需自定义两份资源

示例:

Text('使用系统定义配色')
  .fontColor($r('sys.color.ohos_id_color_text_primary'))

2.2 图片资源适配

  • 使用资源限定词目录:深色模式图片放在 dark/media 目录

  • 通过 $r('app.media.pic_svg') 加载图片,系统自动切换

  • SVG 图标可使用 fillColor 配合系统资源改变颜色

示例:

Image($r('app.media.pic_svg'))
  .width(50)
  .fillColor($r('sys.color.ohos_id_color_text_primary'))

2.3 Web组件适配

2.4 自定义节点适配

  • BuilderNode 和 ComponentContent 需手动传递系统环境变化事件

  • 使用 updateConfiguration() 触发节点更新

示例:

const builderNodeMap: BuilderNode<[Params]>[] = [];

class MyFrameCallback extends FrameCallback {
  onFrame() {
    updateColorMode();
  }
}

function updateColorMode() {
  builderNodeMap.forEach((value) => {
    value.updateConfiguration();
  });
}

aboutToAppear(): void {
  this.getUIContext()?.postFrameCallback(new MyFrameCallback());
}

2.5 应用监听深浅色模式切换事件

  • 无论应用是否跟随系统,均可通过 onConfigurationUpdate 监听

  • 若应用使用 setColorMode 手动设置深浅色,则不会收到该回调

步骤:

  1. 在 AbilityStage 的 onCreate 中保存当前颜色模式到 AppStorage

  2. 在 onConfigurationUpdate 中更新颜色模式。

  3. 在页面中使用 @StorageProp + @Watch 监听变化。

示例:

// AbilityStage.ets
onCreate(): void {
  AppStorage.setOrCreate('currentColorMode', this.context.config.colorMode);
}
onConfigurationUpdate(newConfig: Configuration): void {
  AppStorage.setOrCreate('currentColorMode', newConfig.colorMode);
}
// Page.ets
@StorageProp('currentColorMode') @Watch('onColorModeChange') currentMode: number = ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT;

aboutToAppear(): void {
  if (this.currentMode == ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT) {
    // 浅色模式初始化
  } else {
    // 深色模式初始化
  }
}

onColorModeChange(): void {
  // 同 aboutToAppear 逻辑
}

2.6 局部深浅色适配

  • 使用 WithTheme 容器设置局部颜色模式:

    • ColorMode.SYSTEM:跟随系统

    • ColorMode.LIGHT:固定浅色

    • ColorMode.DARK:固定深色

  • 作用域内组件根据指定模式读取对应资源。

三、应用主动设置深浅色模式

  • 使用 setColorMode 接口固定应用模式,不随系统变化

  • 适用于未适配深色模式的应用,可固定为浅色

示例:

onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
  this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT);
}

四、系统判定应用深浅色模式的规则

  1. 应用调用 setColorMode:以接口设置为准。

  2. 应用未调用 setColorMode

    • 若 dark 目录下有深色资源,则深色模式下自动切换。

    • 若 dark 目录下无资源,则深色模式下仍保持浅色。

强制跟随系统示例:

onCreate(): void {
  this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
  AppStorage.setOrCreate('currentColorMode', this.context.config.colorMode);
}

五、建议与注意事项

5.1 建议方法

  • 使用 AbilityStage 或 Ability 的 onConfigurationUpdate 监听变化

  • 通过状态变量绑定资源,在回调中更新

5.2 不推荐方法

  • 避免在属性设置中通过函数返回值切换颜色,如:

getResource(): string {
  if (colorMode == "dark") {
    return "#FF000000";
  } else {
    return "#FFFFFFFF";
  }
}
  • 这种方式依赖全量重绘,性能不可靠

5.3 优化深浅色模式切换开销(API 20+)

  • 在 module.json5 中配置 metadata 开启高性能切换:

"metadata": [
  {
    "name": "configColorModeChangePerformanceInArkUI",
    "value": "true"
  }
]
  • 开启后需适配以下场景:

    • 实时读取深浅色模式返回不同资源值 → 使用监听回调更新状态变量

    • 自定义主题模式 → 绑定状态变量,在回调中更新

    • 读取成员变量值返回不同资源值 → 绑定状态变量,在回调中更新

5.4 高级组件适配

  • HdsNavigationHdsNavDestinationHdsTabsHdsListItemCard 暂未适配高性能切换,需使用 onConfigurationUpdate 回调处理颜色属性

六、利用反色能力快速适配深色模式(API 20+)

  • 适用于已有部分适配的存量代码,通过反色算法快速实现全量适配

  • 需开启“优化深浅色模式切换开销”

6.1 使用反色能力

  • 调用 OH_ArkUI_SetForceDarkConfig 接口,在 UI 线程中、节点创建前调用

  • 支持自定义反色算法,默认算法为三原色取反

示例:

// CAPI 示例
OH_ArkUI_SetForceDarkConfig(nullptr, true, ArkUI_NodeType::ARKUI_NODE_UNDEFINED, nullptr);
// ArkTS 侧使用
Text("测试反色算法")
  .fontColor(Color.Black)  // 深色模式下自动反色为白色

6.2 接口入参效果

  • OH_ArkUI_SetForceDarkConfig(nullptr, true, ArkUI_NodeType::ARKUI_NODE_UNDEFINED, nullptr):所有组件使用默认反色算法

  • OH_ArkUI_SetForceDarkConfig(nullptr, false, ArkUI_NodeType::ARKUI_NODE_UNDEFINED, nullptr):所有组件停用反色能力

  • 支持针对特定组件类型启用或自定义算法

6.3 反色算法优先级

  1. 深色模式颜色资源配置

  2. 指定组件的自定义反色算法

  3. 所有组件的自定义反色算法

6.4 反色能力逃生通道(API 21+)

  • 可通过 allowForceDark 属性禁用指定组件的自动反色能力

总结

  • 适配深浅色模式分为跟随系统主动设置两种

  • 推荐使用系统资源、资源限定词目录、监听回调等方式实现

  • API 20+ 支持高性能切换和反色能力,可大幅降低适配成本和性能开销

  • 需注意高级组件和反色能力的适配限制

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐