HarmonyOS7 暗黑模式:3 步让你的 App 支持深色主题
文章目录

前言
我之前上架一个 App,审核直接打回来了——原因就是没适配暗黑模式。说实话当时挺不爽的,但用了几天暗黑模式后真香了。HarmonyOS7 的暗黑模式适配其实没那么难,3 步就能搞定,今天手把手教你。
暗黑模式不是"换个黑色背景"那么简单。文字颜色、图片资源、分割线、阴影——所有视觉元素都得跟着调。如果硬编码颜色值,适配起来就是灾难。核心思路是:所有颜色和图片都走资源引用,系统自动帮你切换。
为什么要适配暗黑模式
除了审核要求,还有几个实际好处:
- 省电——OLED 屏幕上黑色像素不发光,暗黑模式真的能省电
- 护眼——夜间使用时白色背景太刺眼,暗黑模式舒服多了
- 高级感——说实话,很多 App 暗黑模式就是比亮色好看
如果实在不想适配,可以强制锁定亮色模式。但这招不推荐,迟早得改。
强制亮色的兜底代码(不推荐,但你知道有这招):

let applicationContext = this.context.getApplicationContext()
applicationContext.setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT)
颜色资源定义
适配暗黑模式的第一步:把所有硬编码的颜色值抽到资源文件里。
亮色模式颜色(base/element/color.json)
{
"color": [
{ "name": "app_background", "value": "#FFFFFF" },
{ "name": "app_title_color", "value": "#000000" },
{ "name": "app_subtitle_color", "value": "#666666" },
{ "name": "app_divider", "value": "#E5E5E5" },
{ "name": "app_primary", "value": "#007DFF" }
]
}
暗黑模式颜色(dark/element/color.json)
{
"color": [
{ "name": "app_background", "value": "#1A1A1A" },
{ "name": "app_title_color", "value": "#E6E6E6" },
{ "name": "app_subtitle_color", "value": "#999999" },
{ "name": "app_divider", "value": "#333333" },
{ "name": "app_primary", "value": "#317AF7" }
]
}

关键点:两个文件的 name 必须完全一致!系统根据 name 匹配,当前模式是暗黑就用 dark 目录下的值,否则用 base 目录的。你代码里只需要写 $r('app.color.app_background'),剩下的系统全包了。
3 步适配
第一步:配置 module.json5
确认你的应用没有强制锁定颜色模式。默认情况下应用会跟随系统,不需要额外配置。如果你之前加了 colorMode 配置,删掉就行。
第二步:资源文件按目录组织
目录结构长这样:
resources/
├── base/
│ └── element/
│ └── color.json ← 亮色模式颜色
├── dark/
│ └── element/
│ └── color.json ← 暗黑模式颜色
└── rawfile/
在代码中引用颜色资源:
@Entry
@Component
struct DarkModeDemo {
build() {
Column() {
Text('标题文字')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor($r('app.color.app_title_color'))
Text('副标题')
.fontSize(14)
.fontColor($r('app.color.app_subtitle_color'))
Divider()
.color($r('app.color.app_divider'))
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.app_background'))
.padding(16)
}
}
注意:背景色、文字色、分割线色——全部用 $r() 引用,一个硬编码的 #xxx 都不要留。
第三步:监听模式切换
有些场景需要在代码中感知暗黑模式变化,比如需要更新 Web 组件的背景色。
import { Configuration, UIAbility, ConfigurationConstant } from '@kit.AbilityKit'
export default class EntryAbility extends UIAbility {
onConfigurationUpdate(newConfig: Configuration): void {
AppStorage.setOrCreate('colorMode', newConfig.colorMode)
}
}
解释:onConfigurationUpdate 在系统模式变化时触发,把当前 colorMode 存到 AppStorage,全局可用。
在页面中监听变化:
@Entry
@Component
struct ThemeAwarePage {
@StorageLink('colorMode')
@Watch('onColorModeChange')
colorMode: ConfigurationConstant.ColorMode =
ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET
onColorModeChange() {
if (this.colorMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK) {
console.info('切换到暗黑模式')
} else {
console.info('切换到亮色模式')
}
}
build() {
Column() {
Text('主题感知页面')
.fontColor($r('app.color.app_title_color'))
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.app_background'))
}
}
@StorageLink 双向绑定 AppStorage 中的值,@Watch 在值变化时触发回调。这两个装饰器配合,实现模式切换的即时响应。
动态切换
有时候用户想在 App 内手动切换主题,不走系统设置。可以这样实现:
@Entry
@Component
struct ManualThemeSwitch {
@StorageLink('colorMode') colorMode: ConfigurationConstant.ColorMode =
ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET
@State isDark: boolean = false
toggleTheme() {
this.isDark = !this.isDark
let applicationContext = getContext(this).getApplicationContext()
if (this.isDark) {
applicationContext.setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_DARK)
} else {
applicationContext.setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT)
}
}
build() {
Column() {
Toggle({ type: ToggleType.Switch, isOn: this.isDark })
.onChange((isOn: boolean) => {
this.toggleTheme()
})
Text('手动切换主题')
.fontColor($r('app.color.app_title_color'))
.margin({ top: 20 })
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.backgroundColor($r('app.color.app_background'))
}
}
setColorMode 可以主动设置应用的颜色模式,不跟随系统。但用了这个方法后,应用就不再自动跟随系统了,除非你再次调用时传入 COLOR_MODE_NOT_SET。
图片资源适配
颜色有 dark 目录,图片也一样。把暗黑模式下的同名图片放到 dark/media/ 目录:
resources/
├── base/
│ ├── element/color.json
│ └── media/
│ └── logo.png ← 亮色模式图片
└── dark/
├── element/color.json
└── media/
└── logo.png ← 暗黑模式图片
代码中正常引用,系统自动切换:
Image($r('app.media.logo'))
.width(100)
.height(100)
对于 SVG 图标,还有更省事的办法——用 fillColor 动态改颜色,不用准备两套图:
Image($r('app.media.icon_svg'))
.width(24)
.height(24)
.fillColor($r('app.color.app_title_color'))
这招真香:一个 SVG 文件配合颜色资源就能适配两种模式,省了双倍图片资源。
系统监听
还有一个更快的方式:直接用系统预置资源。HarmonyOS 提供了 sys.color 系列资源,本身就适配了暗黑模式:
Text('使用系统配色')
.fontColor($r('sys.color.ohos_id_color_text_primary'))
用系统资源的好处是零配置,不用建 dark 目录。缺点是你的 App 会跟着系统风格走,没法做个性化定制。
写在最后
暗黑模式适配的核心就是一句话:别硬编码颜色和图片,全走资源引用。只要做到这一点,3 步就能搞定:
- 建立
dark资源目录 - 所有视觉元素用
$r()引用 - 需要时监听模式变化
提前做好适配,比后面补不知道省多少事。等项目大了再回来改硬编码的颜色值,那个痛苦你不想体验的。
更多推荐

所有评论(0)