在鸿蒙中实现深色/浅色模式切换:从原理到可运行 Demo

摘要

现在几乎所有主流应用都支持"深色模式"和"浅色模式"切换,这已经成了用户习惯。鸿蒙(HarmonyOS)同样提供了两种模式(dark / light),并且支持应用根据系统主题切换,或者应用内手动切换。对于开发者来说,如何配置和管理颜色资源,以及如何在代码里实现动态切换,是必须掌握的技能。

本文会从原理到实战,带你实现一个可运行 Demo,并结合实际应用场景,比如电商、阅读类和社交应用,展示不同的实现方式。

引言

早期很多应用为了"省事",直接写死了颜色值,结果一旦系统切换到深色模式,应用就显得突兀、不协调。鸿蒙的做法比较科学,它提供了 资源限定目录 的机制:在 resources 文件夹里,你可以为不同的颜色模式准备单独的资源文件。

这样一来,应用可以:

  • 跟随系统主题自动切换;
  • 也可以在应用内部提供"主题开关",让用户手动切换。

接下来我们分两部分讲:

配置资源文件 (Light/Dark 模式的颜色文件); 代码层实现动态切换

配置颜色资源

基础做法

首先在 resources 文件夹下新建 Light/Dark 两个目录。方法是右键 -> New Resource Directory -> 勾选 Color Mode ,这样会自动生成 lightdark 两个文件夹。

然后在各自的 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 目录下的颜色值。

动态主题切换实现

跟随系统主题

鸿蒙框架会自动根据系统主题选择 lightdark 资源文件。也就是说,你只要准备好颜色资源,就能实现自动切换。

应用内主动切换

有时候,我们想给用户一个"开关",让他们在应用内手动选择主题。这时需要调用 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()
  • 实际场景里,阅读、电商、社交等应用都能用上主题切换功能,提升用户体验。

写代码时最重要的习惯是:不要写死颜色值,全部走资源引用。这样一来,主题切换就会自然生效,维护起来也轻松。

相关推荐
zhanshuo3 小时前
在鸿蒙里优雅地处理网络错误:从 Demo 到实战案例
harmonyos
whysqwhw8 小时前
鸿蒙分布式投屏
harmonyos
whysqwhw9 小时前
鸿蒙AVSession Kit
harmonyos
whysqwhw11 小时前
鸿蒙各种生命周期
harmonyos
whysqwhw12 小时前
鸿蒙音频编码
harmonyos
whysqwhw12 小时前
鸿蒙音频解码
harmonyos
whysqwhw12 小时前
鸿蒙视频解码
harmonyos
whysqwhw12 小时前
鸿蒙视频编码
harmonyos
ajassi200013 小时前
开源 Arkts 鸿蒙应用 开发(十八)通讯--Ble低功耗蓝牙服务器
华为·开源·harmonyos