HarmonyOS鸿蒙Next中ArkTS如何监听系统深色/浅色主题切换,并动态更新UI颜色?
HarmonyOS鸿蒙Next中ArkTS如何监听系统深色/浅色主题切换,并动态更新UI颜色? 应用支持跟随系统主题,但切换深色模式后,部分自定义组件颜色未更新,需手动重启 App 才生效,如何监听系统深色/浅色主题切换,并动态更新 UI 颜色?
深色模式(Dark Mode)又称为暗色模式,是与日常应用使用过程中的浅色模式(Light Mode)相对应的一种UI主题。深色模式最早来源于人机交互领域的研究和实践,该模式并非简单地将页面背景变为黑色,文字内容变为白色,而是提供一整套适配深色模式的应用配色主题。深色模式相较浅色模式更加柔和,能减少亮度对用户眼睛造成的刺激和疲劳,此外深色模式能在一定程度上降低应用功耗,提升续航表现。
应用深色模式适配,需遵循基本的UX设计原则,保障应用页面内容的易读性、舒适性和一致性,具体可参考深色模式设计原则。应用适配过程主要包含字体颜色、元素背景色等颜色资源的适配,媒体资源如图片图标的适配,以及系统状态栏的适配,此外需要对一些特殊情况如使用了Web组件加载的Web页面进行处理。
实现原理
当系统切换到深色模式后,应用内可能会出现部分内容切换到深色主题的情况,例如状态栏、弹窗背景色、系统控件等,会导致应用内页面效果错乱。
为应对上述情况,需要对应用进行深色模式下的内容适配,目前该适配主要依靠资源目录。当系统对应的设置项发生变化后(如系统语言、深浅色模式等),应用会自动加载对应资源目录下的资源文件。
系统为深色模式预留了dark目录,该目录在应用创建时默认不存在,在进行深色模式适配时,需要开发者在src/main/resources中手动创建出dark目录,将深色模式所需的资源放置到该目录下。对于浅色模式所需的资源,可以放入默认存在的src/main/resources/base目录下。
说明
在进行资源定义时,需要在base目录与dark目录中定义同名的资源。例如在base/element/color.json文件中定义text_color为黑色,在dark/element/color.json文件中定义text_color为白色,那么当深浅色切换时,应用内使用了$(‘app.color.text_color’)作为颜色值的元素会自动切换到对应的颜色,而无需使用其他逻辑判断进行控制。
一般情况下深浅色模式切换不会导致应用界面产生结构上的变化,而是页面结构一致但是采用不同的主题配色、配图等,使得整个应用在切换到深色模式后依然保持自然美观,以下为深色模式适配的UX示例。
图1 深色模式适配UX示例图

从上图中可以看到,在应用进行深色模式适配过程中主要的适配项有颜色资源适配、媒体资源适配、状态栏适配,除此之外若应用内使用了Web组件加载的Web页面,那么还需对Web页面适配深色模式,具体适配方案可点击对应链接跳转到具体章节查看。
目前业内应用向用户提供的深浅色模式切换有以下两种常见方式。
- 应用跟随系统深浅色模式切换 实现上,需要开发者使用setColorMode()方法将ColorMode设置为COLOR_MODE_NOT_SET(未设置颜色模式),然后应用在运行过程中就可以自动感知到系统颜色模式切换,若应用完成了深浅色模式适配,将自动切换到对应的颜色模式。
- 应用内提供手动控制深浅色的开关供用户自行选择 实现上,切换深色模式需要调用setColorMode()方法将ColorMode设置为COLOR_MODE_DARK(深色模式),切换浅色模式需要将ColorMode设置为COLOR_MODE_LIGHT(浅色模式),这样就可以完成对应用深浅色的手动控制。
综上分析,深色模式适配内容如下表所示。
表1 深色模式适配内容
| 适配项 | 适配内容 | 适配方式 |
|---|---|---|
| 颜色资源适配 | 组件背景色,字体颜色等 | 1. 使用受支持的系统资源 2. 使用color.json资源文件 |
| 媒体资源适配 | 应用内使用到的图片、图标等 | 1. SVG类型图标可使用fillColor()属性 2. 使用media资源目录 |
| 状态栏适配 | 深浅模式下不同的状态栏表现,包括状态栏的背景色以及状态栏内时间等内容的字体颜色 | 1. 对应用背景色进行深浅色适配 2. 根据当前深浅色状态动态设置状态栏字体颜色 |
| Web内容适配 | 应用内使用Web组件加载的Web页面 | 参考Web组件设置深色模式 |
在EntryAbility中获取并维护当前深浅色状态,在onCreate时将当前colorMode放在AppStorage中,并在配置变化的onConfigurationUpdate()回调中动态更新深浅色状态。
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
AppStorage.setOrCreate<ConfigurationConstant.ColorMode>('currentColorMode', this.context.config.colorMode);
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
}
// ...
onConfigurationUpdate(newConfig: Configuration): void {
const currentColorMode: ConfigurationConstant.ColorMode | undefined = AppStorage.get('currentColorMode');
if (currentColorMode !== newConfig.colorMode) {
AppStorage.setOrCreate<ConfigurationConstant.ColorMode>('currentColorMode', newConfig.colorMode);
}
}
}
更多详细内容详见开发文档:https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-dark-mode-adaptation
更多关于HarmonyOS鸿蒙Next中ArkTS如何监听系统深色/浅色主题切换,并动态更新UI颜色?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
小伙伴你好,可以在 EntryAbility 中使用 onConfigurationUpdate 事件进行系统深/浅色主题的切换监听。
示例代码:
import { AbilityStage, Configuration } from '@kit.AbilityKit'; // 必须导入 Configuration 类型
export default class MyAbilityStage extends AbilityStage {
onConfigurationUpdate(newConfig: Configuration): void {
console.info(`onConfigurationUpdated, colorMode: ${newConfig.colorMode}`);
}
}
参考文档
1
在ArkTS中,使用window.getLastWindow()获取窗口对象,通过其on('themeChange')方法监听主题变化。
监听回调中,使用window.getLastWindow().theme获取当前系统主题模式,根据返回值(如dark或light)动态更新UI组件的颜色资源。
颜色资源需在resources/base/element/color.json中分别定义深色与浅色值,通过$r('app.color.xxx')引用。
UI组件使用状态变量(@State)绑定颜色,主题切换时更新状态即可触发界面刷新。
在HarmonyOS Next中,可以通过window的colorSchemeChange事件监听系统主题切换,并在回调中动态更新UI颜色。具体步骤如下:
- 监听主题切换事件:在UIAbility的
onWindowStageCreate或自定义组件的aboutToAppear生命周期中,使用window.on('colorSchemeChange', callback)注册监听器。 - 获取当前主题模式:通过
window.getColorScheme()获取当前系统主题(ColorScheme.LIGHT或ColorScheme.DARK)。 - 动态更新UI:在监听器回调中,根据新的主题模式,更新组件的颜色状态变量,触发UI重新渲染。
示例代码(ArkTS):
import { window } from '@kit.ArkUI';
@Entry
@Component
struct MyComponent {
@State currentTheme: ColorScheme = window.getColorScheme(); // 初始化主题状态
aboutToAppear() {
// 监听主题切换事件
window.on('colorSchemeChange', (newScheme: ColorScheme) => {
this.currentTheme = newScheme; // 更新状态变量
// 可在此处添加其他颜色更新逻辑
});
}
build() {
// 根据currentTheme动态设置UI颜色
Column() {
Text('当前主题:' + (this.currentTheme === ColorScheme.DARK ? '深色' : '浅色'))
.fontColor(this.currentTheme === ColorScheme.DARK ? Color.White : Color.Black)
}
.backgroundColor(this.currentTheme === ColorScheme.DARK ? Color.Black : Color.White)
}
}
注意事项:
- 自定义组件需使用
@State、@Prop等装饰器管理颜色变量,确保主题切换时能触发UI更新。 - 若组件颜色未更新,检查是否在监听回调中正确更新了状态变量,或尝试使用
window.off('colorSchemeChange')移除旧监听器避免重复注册。 - 对于全局颜色配置,建议使用
AppStorage或自定义管理类统一处理主题色值。

