HarmonyOS 鸿蒙Next主题管理深色模式如何实现切换?暗黑模式适配指南

HarmonyOS 鸿蒙Next主题管理深色模式如何实现切换?暗黑模式适配指南 harmonyOS 5.0,DevEco Studio 5.0

  • 需要实现应用的深色/浅色主题切换功能
  • 不清楚如何监听系统主题变化
  • 希望了解颜色资源的正确配置方式

希望了解HarmonyOS主题管理的完整实现方案,包括颜色资源配置、主题切换和系统主题监听

3 回复

1. 颜色资源配置

resources/base/element/color.json 中定义浅色主题颜色:

{
  "color": [
    { "name": "primary", "value": "#36e27b" },
    { "name": "background", "value": "#f6f8f7" },
    { "name": "surface", "value": "#ffffff" },
    { "name": "text_primary", "value": "#111714" },
    { "name": "text_secondary", "value": "#6b7280" },
    { "name": "divider", "value": "#e5e7eb" }
  ]
}

resources/dark/element/color.json 中定义深色主题颜色:

{
  "color": [
    { "name": "primary", "value": "#36e27b" },
    { "name": "background", "value": "#112117" },
    { "name": "surface", "value": "#1C2E24" },
    { "name": "text_primary", "value": "#ffffff" },
    { "name": "text_secondary", "value": "#9eb7a8" },
    { "name": "divider", "value": "#1a3d2a" }
  ]
}

2. 主题管理服务

3. 在EntryAbility中监听系统主题

// EntryAbility.ets
import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit'
import { ThemeManager } from '../utils/ThemeManager'

export default class EntryAbility extends UIAbility {

  async onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): Promise<void> {
    // 初始化主题管理器
    await ThemeManager.getInstance().init(this.context)
  
    // 获取当前系统主题
    const colorMode = this.context.config.colorMode
    ThemeManager.getInstance().updateSystemColorMode(colorMode)
  }

  // 监听系统配置变化
  onConfigurationUpdate(newConfig: Configuration): void {
    if (newConfig.colorMode !== undefined) {
      ThemeManager.getInstance().updateSystemColorMode(newConfig.colorMode)
    }
  }
}

4. 主题设置页面

import { ThemeManager, ThemeMode } from '../utils/ThemeManager'

@Entry
@Component
struct ThemeSettingsPage {
  @State currentMode: ThemeMode = ThemeMode.SYSTEM
  @State isDark: boolean = false

  private themeManager = ThemeManager.getInstance()

  aboutToAppear(): void {
    this.currentMode = this.themeManager.getThemeMode()
    this.isDark = this.themeManager.isDarkMode()
  
    // 监听主题变化
    this.themeManager.addListener((isDark) => {
      this.isDark = isDark
    })
  }

  build() {
    Column({ space: 16 }) {
      Text('主题设置')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .fontColor($r('app.color.text_primary'))
        .width('100%')
      
      // 主题选项
      Column({ space: 8 }) {
        this.ThemeOption('跟随系统', ThemeMode.SYSTEM)
        this.ThemeOption('浅色模式', ThemeMode.LIGHT)
        this.ThemeOption('深色模式', ThemeMode.DARK)
      }
      .padding(16)
      .backgroundColor($r('app.color.surface'))
      .borderRadius(16)
      
      // 当前状态预览
      Column({ space: 8 }) {
        Text('当前状态')
          .fontSize(14)
          .fontColor($r('app.color.text_secondary'))
        Text(this.isDark ? '深色模式' : '浅色模式')
          .fontSize(16)
          .fontColor($r('app.color.text_primary'))
      }
      .padding(16)
      .backgroundColor($r('app.color.surface'))
      .borderRadius(16)
      .width('100%')
    }
    .width('100%')
    .height('100%')
    .padding(16)
    .backgroundColor($r('app.color.background'))
  }

  @Builder
  ThemeOption(title: string, mode: ThemeMode) {
    Row() {
      Text(title)
        .fontSize(16)
        .fontColor($r('app.color.text_primary'))
      
      Blank()
      
      Radio({ value: mode, group: 'theme' })
        .checked(this.currentMode === mode)
        .onChange((isChecked: boolean) => {
          if (isChecked) {
            this.currentMode = mode
            this.themeManager.setThemeMode(mode)
          }
        })
    }
    .width('100%')
    .height(48)
    .padding({ left: 12, right: 12 })
  }
}
import { preferences } from '@kit.ArkData'
import { ConfigurationConstant } from '@kit.AbilityKit'

// 主题模式枚举
export enum ThemeMode {
  SYSTEM = 'system', // 跟随系统
  LIGHT = 'light',   // 浅色
  DARK = 'dark'      // 深色
}

// 主题管理类
export class ThemeManager {
  private static instance: ThemeManager
  private context: Context | null = null
  private currentMode: ThemeMode = ThemeMode.SYSTEM
  private systemIsDark: boolean = false
  private listeners: ((isDark: boolean) => void)[] = []

  static getInstance(): ThemeManager {
    if (!ThemeManager.instance) {
      ThemeManager.instance = new ThemeManager()
    }
    return ThemeManager.instance
  }

  // 初始化
  async init(context: Context): Promise<void> {
    this.context = context
    await this.loadSavedMode()
  }

  // 加载保存的主题模式
  private async loadSavedMode(): Promise<void> {
    if (!this.context) return
  
    try {
      const prefs = await preferences.getPreferences(this.context, { name: 'settings' })
      const mode = await prefs.get('themeMode', ThemeMode.SYSTEM) as ThemeMode
      this.currentMode = mode
    } catch (err) {
      console.error('加载主题设置失败:', err)
    }
  }

  // 设置主题模式
  async setThemeMode(mode: ThemeMode): Promise<void> {
    this.currentMode = mode
  
    if (this.context) {
      const prefs = await preferences.getPreferences(this.context, { name: 'settings' })
      await prefs.put('themeMode', mode)
      await prefs.flush()
    }
  
    this.notifyListeners()
  }

  // 更新系统主题状态
  updateSystemColorMode(colorMode: ConfigurationConstant.ColorMode): void {
    this.systemIsDark = colorMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK
  
    if (this.currentMode === ThemeMode.SYSTEM) {
      this.notifyListeners()
    }
  }

  // 获取当前是否为深色模式
  isDarkMode(): boolean {
    switch (this.currentMode) {
      case ThemeMode.LIGHT:
        return false
      case ThemeMode.DARK:
        return true
      case ThemeMode.SYSTEM:
      default:
        return this.systemIsDark
    }
  }

  // 获取当前主题模式
  getThemeMode(): ThemeMode {
    return this.currentMode
  }

  // 添加监听器
  addListener(listener: (isDark: boolean) => void): void {
    this.listeners.push(listener)
  }

  // 移除监听器
  removeListener(listener: (isDark: boolean) => void): void {
    const index = this.listeners.indexOf(listener)
    if (index > -1) {
      this.listeners.splice(index, 1)
    }
  }

  // 通知所有监听器
  private notifyListeners(): void {
    const isDark = this.isDarkMode()
    this.listeners.forEach(listener => listener(isDark))
  }
}

5. 在组件中使用主题颜色

@Component
struct ThemedCard {
  build() {
    Column({ space: 12 }) {
      Text('标题')
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
        .fontColor($r('app.color.text_primary')) // 自动适配主题
    
      Text('描述内容')
        .fontSize(14)
        .fontColor($r('app.color.text_secondary')) // 自动适配主题
    
      Divider()
        .color($r('app.color.divider')) // 自动适配主题
    }
    .padding(16)
    .backgroundColor($r('app.color.surface')) // 自动适配主题
    .borderRadius(16)
  }
}

更多关于HarmonyOS 鸿蒙Next主题管理深色模式如何实现切换?暗黑模式适配指南的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


HarmonyOS Next主题管理通过ThemeManager模块实现深色模式切换。系统提供明暗主题资源目录(如resources/theme/dark),开发者需在config.json中配置主题资源。使用ThemeManager.applyTheme()方法动态切换主题,系统会自动加载对应资源。适配时需为所有UI组件定义明暗两套资源,确保颜色、图标等元素在不同模式下正确显示。系统主题变化会触发onConfigurationUpdate回调,可在此处理界面刷新逻辑。

在HarmonyOS Next中,实现深色/浅色主题切换主要依赖于其全新的主题管理框架。以下是核心实现方案:

1. 颜色资源配置

resources/base/element/目录下的color.json文件中,必须使用语义化颜色命名,并分别定义浅色(light)和深色(dark)模式下的具体色值。

示例 (color.json):

{
  "color": [
    {
      "name": "background_primary",
      "value": "#FFFFFF",
      "dark": "#000000"
    },
    {
      "name": "text_primary",
      "value": "#1A1A1A",
      "dark": "#F0F0F0"
    }
  ]
}

在UI组件中,通过$r('app.color.background_primary')引用这些语义化颜色资源,系统会根据当前主题自动匹配对应的色值。

2. 应用内主题切换

应用可以主动设置自身的主题,独立于系统主题。

核心API (themeManager):

import { themeManager } from '@kit.ArkUI';

// 获取当前应用主题
let currentTheme: themeManager.ThemeMode = themeManager.getTheme();

// 设置为深色主题
themeManager.setTheme(themeManager.ThemeMode.DARK);

// 设置为浅色主题
themeManager.setTheme(themeManager.ThemeMode.LIGHT);

// 跟随系统主题
themeManager.setTheme(themeManager.ThemeMode.AUTO);

当调用setTheme后,所有使用了语义化颜色的UI组件会自动刷新,无需手动更新每个组件。

3. 监听系统主题变化

应用可以注册监听器,实时响应系统主题的变更。

监听与取消监听:

import { themeManager } from '@kit.ArkUI';

// 定义监听回调函数
let systemThemeCallback = (theme: themeManager.ThemeMode): void => {
  console.log(`System theme changed to: ${theme}`);
  // 可以在此处执行一些额外的逻辑,但UI颜色会自动适配
};

// 注册监听(例如在aboutToAppear生命周期中)
themeManager.on('themeChange', systemThemeCallback);

// 取消监听(例如在aboutToDisappear生命周期中)
themeManager.off('themeChange', systemThemeCallback);

当系统主题改变且应用主题设置为ThemeMode.AUTO(跟随系统)时,此回调会被触发。

完整流程总结

  1. 配置资源:在color.json中为所有关键颜色定义浅色和深色值。
  2. UI开发:在ArkUI组件中统一引用语义化颜色名称。
  3. 主题控制:使用themeManager.setTheme()管理应用自身主题(深色、浅色或自动跟随系统)。
  4. 监听系统:通过themeManager.on('themeChange', callback)监听系统主题变化,以便在需要时执行业务逻辑。

按照此方案,应用的主题切换将由系统框架自动完成渲染更新,开发者只需关注颜色资源的定义和主题模式的设置即可。

回到顶部