深色模式:ResourceManager 如何选资源及如何手动控制

前言

“深色模式一切全系统跟着变"是 HarmonyOS 的默认行为——ResourceManager 根据系统 colorMode 自动选择 resources/dark/element/color.json 里的深色资源。但很多场景需要"应用内不跟随系统"或"单个页面固定浅色”。本文讲清自动选择的原理,以及如何用 Configuration 手动控制深浅色。

问题描述

现象与疑问:

  • 系统切深色,应用所有颜色自动变——这是怎么做到的?
  • 想让某个页面永远浅色,或应用内提供"浅色/深色/跟随系统"三档开关,怎么做?
  • 设置了深色资源,但切换后 UI 没刷新——为什么?

根因:颜色等资源按"资源配置限定词目录"管理,dark 目录下的资源在系统 colorMode 为 DARK 时被选中。getContext().resourceManager 取的是当前 configuration 下的值;如果切换后没触发重渲染,UI 当然不更新。

细节解析

三层机制:

  1. 资源自动选择resources/base/element/color.json(浅色)与 resources/dark/element/color.json(深色)同名 name 对应,系统按 colorMode 自动选。$r('app.color.bg') 在运行时解析到当前模式的值。
  2. 应用级强制:用 configuration.setColorMode 把整个应用锁到 DARK/LIGHT,覆盖系统。
  3. 页面级不跟随:该页面不通过 $r() 取资源,而是写死色值或用 @StorageProp('darkMode') 自管,绕过 ResourceManager 自动选择。

易错点:不要在 aboutToAppear 里把颜色值缓存到变量——要每次 this.bgColor = $r('app.color.bg') 实时取,否则切色不生效。切换后需 updateConfiguration 触发重渲染。

示例代码

资源定义:

// resources/base/element/color.json
{
  "color": [
    { "name": "bg", "value": "#FFFFFF" },
    { "name": "text", "value": "#000000" }
  ]
}
// resources/dark/element/color.json
{
  "color": [
    { "name": "bg", "value": "#000000" },
    { "name": "text", "value": "#FFFFFF" }
  ]
}

页面用资源(跟随系统):

@Entry
@Component
struct HomePage {
  @State bg: Resource = $r('app.color.bg');
  @State txt: Resource = $r('app.color.text');

  build() {
    Column() {
      Text('跟随系统的文字').fontColor(this.txt)
    }.backgroundColor(this.bg)
  }
}

应用内强制深色(不跟随系统):

import { configuration } from '@kit.ResourceManagerKit';
import { ConfigurationConstant } from '@kit.ResourceManagerKit';
import { common } from '@kit.AbilityKit';

const ctx = getContext(this) as common.UIAbilityContext;
// 手动锁定为深色
configuration.setColorMode(ctx, ConfigurationConstant.ColorMode.COLOR_MODE_DARK);
// 切回跟随系统:COLOR_MODE_UNDEFINED

监听系统切换并刷新:

// 在 EntryAbility 里监听 configuration 变化
this.context.getApplicationContext().on('environment', () => {
  // 系统深浅色变了,重新取资源并触发页面刷新
});

总结

  • 跟随系统是默认,靠 base/dark 资源目录自动选。
  • 应用级锁定用 configuration.setColorMode;页面级不跟随就别用 $r()
  • 别缓存颜色值,每次实时取 $r();切换后确保触发重渲染。
  • 验证:系统设置切深色,应自动变;应用内 setColorMode(DARK) 应强制变,与系统无关。
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐