
摘要
现在几乎所有主流应用都支持"深色模式"和"浅色模式"切换,这已经成了用户习惯。鸿蒙(HarmonyOS)同样提供了两种模式(dark / light),并且支持应用根据系统主题切换,或者应用内手动切换。对于开发者来说,如何配置和管理颜色资源,以及如何在代码里实现动态切换,是必须掌握的技能。
本文会从原理到实战,带你实现一个可运行 Demo,并结合实际应用场景,比如电商、阅读类和社交应用,展示不同的实现方式。
引言
早期很多应用为了"省事",直接写死了颜色值,结果一旦系统切换到深色模式,应用就显得突兀、不协调。鸿蒙的做法比较科学,它提供了 资源限定目录 的机制:在 resources
文件夹里,你可以为不同的颜色模式准备单独的资源文件。
这样一来,应用可以:
- 跟随系统主题自动切换;
- 也可以在应用内部提供"主题开关",让用户手动切换。
接下来我们分两部分讲:
配置资源文件 (Light/Dark 模式的颜色文件); 代码层实现动态切换。
配置颜色资源
基础做法
首先在 resources
文件夹下新建 Light/Dark 两个目录。方法是右键 -> New Resource Directory
-> 勾选 Color Mode ,这样会自动生成 light
和 dark
两个文件夹。
然后在各自的 element
文件夹下创建 color.json
文件,格式如下:
light/element/color.json
json
{
"color": [
{
"name": "background",
"value": "#FFFFFF"
},
{
"name": "font_color",
"value": "#000000"
},
{
"name": "button_background",
"value": "#0000FF"
}
]
}
dark/element/color.json
json
{
"color": [
{
"name": "background",
"value": "#000000"
},
{
"name": "font_color",
"value": "#FFFFFF"
},
{
"name": "button_background",
"value": "#1E90FF"
}
]
}
这样就完成了"颜色资源"的配置。没配置的情况下,应用会默认使用 base
目录下的颜色值。
动态主题切换实现
跟随系统主题
鸿蒙框架会自动根据系统主题选择 light
或 dark
资源文件。也就是说,你只要准备好颜色资源,就能实现自动切换。
应用内主动切换
有时候,我们想给用户一个"开关",让他们在应用内手动选择主题。这时需要调用 UIAppearance
相关接口。
下面是一个最小化 Demo:
ts
// Index.ets
import UIAppearance from '@ohos.arkui.UIAppearance';
@Entry
@Component
struct Index {
@State isDark: boolean = false;
build() {
Column({ space: 20 }) {
Button(this.isDark ? '切换到浅色模式' : '切换到深色模式')
.onClick(() => {
this.isDark = !this.isDark;
UIAppearance.setColorMode(this.isDark ? 'dark' : 'light');
})
Text('当前主题:' + (this.isDark ? '深色模式' : '浅色模式'))
.fontColor($r('app.color.font_color'))
.backgroundColor($r('app.color.background'))
.fontSize(20)
.padding(20)
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.background'))
}
}
在上面的代码里:
- 我们定义了一个
isDark
状态来表示当前主题; - 点击按钮后,调用
UIAppearance.setColorMode
主动切换; - 文本和背景颜色都使用资源引用
$r('app.color.xxx')
,这样能保证跟随主题变化。
场景应用
电商应用:商品展示
在电商类应用中,白天浏览商品时用浅色背景更舒服,晚上则希望用深色模式减少视觉刺激。
ts
Text('¥199.00')
.fontColor($r('app.color.font_color'))
.fontSize(24)
.backgroundColor($r('app.color.background'))
解析:这里字体和背景颜色都是从资源文件里获取的,系统切换主题时自动生效。
阅读应用:夜间模式
阅读类应用通常会提供独立的"夜间模式开关"。即便系统是浅色模式,用户也可能选择在夜间用深色主题。
ts
Toggle({ name: '夜间模式' }, this.isDark)
.onChange((value: boolean) => {
this.isDark = value;
UIAppearance.setColorMode(value ? 'dark' : 'light');
})
解析:Toggle(开关组件)直接控制主题切换,体验和阅读器常见功能一致。
社交应用:个人设置页面
在社交应用里,主题切换一般放在"设置"页面。
ts
Row() {
Text('深色模式')
.fontSize(18)
Switch({ checked: this.isDark })
.onChange((val: boolean) => {
this.isDark = val;
UIAppearance.setColorMode(val ? 'dark' : 'light');
})
}
解析:Switch 控件切换主题,同时更新全局 UI。用户在"设置"里调整一次,就能影响所有页面。
常见问题(Q&A)
Q1: 如果没配置 dark
文件夹会怎样? A: 系统会默认使用 base
下的资源,也就是说不会报错,但主题切换没效果。
Q2: 为什么有时候颜色不跟随主题? A: 很可能是你在组件里直接写死了颜色值,比如 #FFFFFF
,而不是引用 $r('app.color.xxx')
。
Q3: 应用主动切换和系统主题冲突怎么办? A: 一般来说,跟随系统是默认行为。如果你在应用里提供了"手动开关",就要在逻辑上优先考虑用户的选择。
总结
鸿蒙的动态主题切换本质上依赖于 资源限定目录 + UIAppearance API。
- 想跟随系统?准备好
light/dark
资源就行。 - 想主动切换?调用
UIAppearance.setColorMode()
。 - 实际场景里,阅读、电商、社交等应用都能用上主题切换功能,提升用户体验。
写代码时最重要的习惯是:不要写死颜色值,全部走资源引用。这样一来,主题切换就会自然生效,维护起来也轻松。