HarmonyOS 鸿蒙Next深色模式适配持久化实现方式

HarmonyOS 鸿蒙Next深色模式适配持久化实现方式 调用ApplicationContext.setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_DARK)将应用配色方案设为深色模式后,仅运行期间有效。退出应用重新进入后,设置丢失,深色模式失效。如何实现设置深色模式后,下次进入应用能保留配置?

3 回复

ApplicationContext.setColorMode()

只是临时设置应用的配色模式,不会持久化到存储中。应用重启后,系统会恢复为默认配置。

解决方案

需要结合 数据持久化 + 应用启动时恢复配置 来实现。HarmonyOS 提供了多种数据持久化方式,推荐使用 Preferences(首选项)。


完整实现方案

方案一:使用 Preferences

  1. 创建配置管理工具类
// utils/ThemeManager.ets

import { preferences } from '@kit.ArkData';
import { ConfigurationConstant } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';

export class ThemeManager {
  private static instance: ThemeManager;
  private dataPreferences: preferences.Preferences | null = null;
  private context: common.Context | null = null;
  private readonly PREFERENCE_NAME = 'app_settings';
  private readonly KEY_COLOR_MODE = 'color_mode';

  // 单例模式
  public static getInstance(): ThemeManager {
    if (!ThemeManager.instance) {
      ThemeManager.instance = new ThemeManager();
    }
    return ThemeManager.instance;
  }

  // 初始化(在应用启动时调用)
  async init(context: common.Context): Promise<void> {
    this.context = context;
    try {
      // 获取 Preferences 实例
      this.dataPreferences = await preferences.getPreferences(
        context,
        this.PREFERENCE_NAME
      );
      console.info('ThemeManager 初始化成功');
    } catch (error) {
      console.error('ThemeManager 初始化失败:', error);
    }
  }

  // 保存深色模式配置
  async saveColorMode(colorMode: ConfigurationConstant.ColorMode): Promise<void> {
    if (!this.dataPreferences) {
      console.error('Preferences 未初始化');
      return;
    }
    try {
      // 保存到 Preferences
      await this.dataPreferences.put(this.KEY_COLOR_MODE, colorMode);
      // 持久化到磁盘
      await this.dataPreferences.flush();
      console.info('深色模式配置已保存:', colorMode);
    } catch (error) {
      console.error('保存深色模式配置失败:', error);
    }
  }

  // 获取保存的深色模式配置
  async getColorMode(): Promise<ConfigurationConstant.ColorMode> {
    if (!this.dataPreferences) {
      console.error('Preferences 未初始化');
      return ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET;
    }
    try {
      // 从 Preferences 读取
      const colorMode = await this.dataPreferences.get(
        this.KEY_COLOR_MODE,
        ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET
      ) as ConfigurationConstant.ColorMode;
      console.info('读取到的深色模式配置:', colorMode);
      return colorMode;
    } catch (error) {
      console.error('读取深色模式配置失败:', error);
      return ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET;
    }
  }

  // 应用深色模式配置
  async applyColorMode(colorMode: ConfigurationConstant.ColorMode): Promise<void> {
    if (!this.context) {
      console.error('Context 未初始化');
      return;
    }
    try {
      // 获取 ApplicationContext
      const applicationContext = this.context.getApplicationContext();
      // 设置深色模式
      applicationContext.setColorMode(colorMode);
      // 保存配置
      await this.saveColorMode(colorMode);
      console.info('深色模式已应用:', colorMode);
    } catch (error) {
      console.error('应用深色模式失败:', error);
    }
  }

  // 恢复保存的深色模式配置(在应用启动时调用)
  async restoreColorMode(): Promise<void> {
    if (!this.context) {
      console.error('Context 未初始化');
      return;
    }
    try {
      // 读取保存的配置
      const savedColorMode = await this.getColorMode();
      // 如果有保存的配置,则应用
      if (savedColorMode !== ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET) {
        const applicationContext = this.context.getApplicationContext();
        applicationContext.setColorMode(savedColorMode);
        console.info('已恢复深色模式配置:', savedColorMode);
      } else {
        console.info('未找到保存的深色模式配置,使用默认设置');
      }
    } catch (error) {
      console.error('恢复深色模式配置失败:', error);
    }
  }

  // 切换深色模式
  async toggleColorMode(): Promise<void> {
    const currentMode = await this.getColorMode();
    // 切换模式
    const newMode = currentMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK
      ? ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT
      : ConfigurationConstant.ColorMode.COLOR_MODE_DARK;
    // 应用新模式
    await this.applyColorMode(newMode);
  }

  // 检查当前是否为深色模式
  async isDarkMode(): Promise<boolean> {
    const colorMode = await this.getColorMode();
    return colorMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK;
  }
}

  1. 在 EntryAbility 中初始化并恢复配置
// entryability/EntryAbility.ets

import { UIAbility, Want, AbilityConstant } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { ThemeManager } from '../utils/ThemeManager';

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    hilog.info(0x0000, 'testTag', 'Ability onCreate');
  }

  onDestroy(): void {
    hilog.info(0x0000, 'testTag', 'Ability onDestroy');
  }

  async onWindowStageCreate(windowStage: window.WindowStage): void {
    hilog.info(0x0000, 'testTag', 'Ability onWindowStageCreate');
    // ✅ 关键步骤1:初始化 ThemeManager
    const themeManager = ThemeManager.getInstance();
    await themeManager.init(this.context);
    // ✅ 关键步骤2:恢复保存的深色模式配置
    await themeManager.restoreColorMode();
    // 加载主页面
    windowStage.loadContent('pages/Index', (err) => {
      if (err.code) {
        hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s',
          JSON.stringify(err) ?? '');
        return;
      }
      hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.');
    });
  }

  onWindowStageDestroy(): void {
    hilog.info(0x0000, 'testTag', 'Ability onWindowStageDestroy');
  }

  onForeground(): void {
    hilog.info(0x0000, 'testTag', 'Ability onForeground');
  }

  onBackground(): void {
    hilog.info(0x0000, 'testTag', 'Ability onBackground');
  }
}

  1. 在页面中使用
// pages/Index.ets

import { ConfigurationConstant } from '@kit.AbilityKit';
import { ThemeManager } from '../utils/ThemeManager';

@Entry
@Component
struct Index {
  @State isDarkMode: boolean = false;

  async aboutToAppear() {
    // 获取当前深色模式状态
    const themeManager = ThemeManager.getInstance();
    this.isDarkMode = await themeManager.isDarkMode();
  }

  build() {
    Column({ space: 20 }) {
      Text('深色模式设置')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)

      Row({ space: 10 }) {
        Text('当前模式:')
          .fontSize(18)
        Text(this.isDarkMode ? '深色' : '浅色')
          .fontSize(18)
          .fontColor(this.isDarkMode ? Color.White : Color.Black)
      }

      // 切换按钮
      Button('切换深色模式')
        .onClick(async () => {
          const themeManager = ThemeManager.getInstance();
          await themeManager.toggleColorMode();
          // 更新状态
          this.isDarkMode = await themeManager.isDarkMode();
        })

      // 直接设置深色模式
      Button('设置为深色模式')
        .onClick(async () => {
          const themeManager = ThemeManager.getInstance();
          await themeManager.applyColorMode(
            ConfigurationConstant.ColorMode.COLOR_MODE_DARK
          );
          this.isDarkMode = true;
        })

      // 直接设置浅色模式
      Button('设置为浅色模式')
        .onClick(async () => {
          const themeManager = ThemeManager.getInstance();
          await themeManager.applyColorMode(
            ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT
          );
          this.isDarkMode = false;
        })

      // 跟随系统设置
      Button('跟随系统')
        .onClick(async () => {
          const themeManager = ThemeManager.getInstance();
          await themeManager.applyColorMode(
            ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET
          );
          // 重新读取当前状态
          this.isDarkMode = await themeManager.isDarkMode();
        })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .padding(20)
    .backgroundColor(this.isDarkMode ? '#1F1F1F' : '#F5F5F5')
  }
}

方案二:使用 AppStorage(应用内全局状态 + Preferences)

如果需要在应用内多个页面共享深色模式状态,可以结合 AppStorage:

// utils/ThemeManagerWithAppStorage.ets

import { preferences } from '@kit.ArkData';
import { ConfigurationConstant } from '@kit.AbilityKit';
import { common } from '@kit.AbilityKit';

export class ThemeManagerWithAppStorage {
  private static instance: ThemeManagerWithAppStorage;
  private dataPreferences: preferences.Preferences | null = null;
  private context: common.Context | null = null;
  private readonly PREFERENCE_NAME = 'app_settings';
  private readonly KEY_COLOR_MODE = 'color_mode';
  private readonly APP_STORAGE_KEY = 'isDarkMode';

  public static getInstance(): ThemeManagerWithAppStorage {
    if (!ThemeManagerWithAppStorage.instance) {
      ThemeManagerWithAppStorage.instance = new ThemeManagerWithAppStorage();
    }
    return ThemeManagerWithAppStorage.instance;
  }

  async init(context: common.Context): Promise<void> {
    this.context = context;
    try {
      this.dataPreferences = await preferences.getPreferences(
        context,
        this.PREFERENCE_NAME
      );
      console.info('ThemeManagerWithAppStorage 初始化成功');
    } catch (error) {
      console.error('ThemeManagerWithAppStorage 初始化失败:', error);
    }
  }

  // 应用深色模式并保存到 AppStorage
  async applyColorMode(colorMode: ConfigurationConstant.ColorMode): Promise<void> {
    if (!this.context || !this.dataPreferences) {
      console.error('未初始化');
      return;
    }
    try {
      // 设置系统配色
      const applicationContext = this.context.getApplicationContext();
      applicationContext.setColorMode(colorMode);
      // 保存到 Preferences
      await this.dataPreferences.put(this.KEY_COLOR_MODE, colorMode);
      await this.dataPreferences.flush();
      // 更新 AppStorage(全局状态)
      const isDark = colorMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK;
      AppStorage.setOrCreate(this.APP_STORAGE_KEY, isDark);
      console.info('深色模式已应用并保存:', colorMode);
    } catch (error) {
      console.error('应用深色模式失败:', error);
    }
  }

  // 恢复配置
  async restoreColorMode(): Promise<void> {
    if (!this.context || !this.dataPreferences) {
      console.error('未初始化');
      return;
    }
    try {
      // 读取保存的配置
      const savedColorMode = await this.dataPreferences.get(
        this.KEY_COLOR_MODE,
        ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET
      ) as ConfigurationConstant.ColorMode;
      if (savedColorMode !== ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET) {
        // 应用配置
        const applicationContext = this.context.getApplicationContext();
        applicationContext.setColorMode(savedColorMode);
        // 更新 AppStorage
        const isDark = savedColorMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK;
        AppStorage.setOrCreate(this.APP_STORAGE_KEY, isDark);
        console.info('已恢复深色模式配置:', savedColorMode);
      }
    } catch (error) {
      console.error('恢复深色模式配置失败:', error);
    }
  }
}

在页面中使用 AppStorage:

@Entry
@Component
struct Index {
  // 从 AppStorage 读取全局状态
  @StorageLink('isDarkMode') isDarkMode: boolean = false;

  build() {
    Column({ space: 20 }) {
      Text('深色模式: ' + (this.isDarkMode ? '开启' : '关闭'))
        .fontSize(24)
      Button('切换深色模式')
        .onClick(async () => {
          const themeManager = ThemeManagerWithAppStorage.getInstance();
          const newMode = this.isDarkMode
            ? ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT
            : ConfigurationConstant.ColorMode.COLOR_MODE_DARK;
          await themeManager.applyColorMode(newMode);
          // AppStorage 会自动更新 this.isDarkMode
        })
    }
    .width('100%')
    .height('100%')
    .backgroundColor(this.isDarkMode ? '#1F1F1F' : '#F5F5F5')
  }
}

关键要点总结

必须做的:

  1. 在 Ability 启动时恢复配置

async onWindowStageCreate(windowStage: window.WindowStage) { await themeManager.init(this.context); await themeManager.restoreColorMode(); // 关键! // … }

  1. 每次修改配置时都要保存

applicationContext.setColorMode(colorMode); // 临时设置 await themeManager.saveColorMode(colorMode); // 持久化保存

  1. 使用 Preferences 的 flush() 方法确保写入磁盘

await dataPreferences.put(KEY_COLOR_MODE, colorMode); await dataPreferences.flush(); // 确保持久化

常见错误:

  1. 只调用 setColorMode() 不保存
  2. 没有在 Ability 启动时恢复配置
  3. 忘记调用 flush() 导致配置未写入磁盘

更多关于HarmonyOS 鸿蒙Next深色模式适配持久化实现方式的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


鸿蒙Next深色模式适配持久化可通过AbilityStage和UIAbility结合Preferences数据管理实现。在应用启动时,使用Preferences读取存储的主题设置,调用windowClass.setWindowBackgroundColor或UIService.setAppTheme动态切换。持久化存储利用Preferences.put()方法保存用户选择的模式,确保应用重启后主题一致。具体实现涉及获取窗口实例、监听系统主题变化,并在onWindowStageCreate生命周期中应用配置。

在HarmonyOS Next中,要实现深色模式设置的持久化,可以使用Preferences分布式数据对象来保存用户选择的配色模式。以下是具体实现步骤:

  1. 使用Preferences存储配置

    • 在设置深色模式时,将配置值写入Preferences:
    import preferences from '[@ohos](/user/ohos).data.preferences';
    
    let preferences = await preferences.getPreferences(context, 'colorModePrefs');
    await preferences.put('colorMode', ConfigurationConstant.ColorMode.COLOR_MODE_DARK);
    await preferences.flush();
    
    • 应用启动时读取Preferences中的配置并应用:
    let savedMode = await preferences.get('colorMode', ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT);
    ApplicationContext.setColorMode(savedMode);
    
  2. 结合应用生命周期管理

    • onCreate或应用初始化阶段加载保存的配置,确保启动时立即生效。

这种方式可以确保用户退出应用后再次进入时,深色模式配置仍然保留。

回到顶部