及时做APP开发实战(十)-深浅色主题适配实现 及时做APP开发实战(十)-深浅色主题适配实现本文将详细介绍如何在HarmonyOS NEXT中实现深浅色主题适配让应用跟随系统主题动态切换。一、需求背景1.1 功能需求现代应用需要支持深浅色主题切换提供更好的用户体验┌─────────────────────────────────────┐ │ 主题适配需求 │ ├─────────────────────────────────────┤ │ • 跟随系统主题自动切换 │ │ • 动态更新所有UI组件颜色 │ │ • 保持主题切换的流畅性 │ │ • 抽离颜色常量便于维护 │ └─────────────────────────────────────┘1.2 技术方案HarmonyOS提供Configuration.colorMode监听系统主题变化模式说明COLOR_MODE_LIGHT浅色模式COLOR_MODE_DARK深色模式COLOR_MODE_NOT_SET跟随系统二、主题颜色设计2.1 颜色体系规划【图1颜色体系】┌─────────────────────────────────────┐ │ 颜色分类 │ ├─────────────────────────────────────┤ │ 背景色 │ │ - 页面背景 background │ │ - 卡片背景 cardBackground │ │ │ │ 文本色 │ │ - 主文本 textPrimary │ │ - 次要文本 textSecondary │ │ - 提示文本 textHint │ │ │ │ 主题色 │ │ - 主色 primary │ │ - 主色浅 primaryLight │ │ - 成功色 success │ │ - 警告色 warning │ │ │ │ 边框色 │ │ - 边框 border │ │ - 分割线 divider │ └─────────────────────────────────────┘2.2 ThemeColors接口定义exportinterfaceThemeColors{// 背景色background:string;cardBackground:string;// 文本色textPrimary:string;textSecondary:string;textHint:string;// 主题色primary:string;primaryLight:string;success:string;warning:string;// 边框色border:string;divider:string;}2.3 浅色主题配置constLightTheme:ThemeColors{background:#F5F5F5,cardBackground:#FFFFFF,textPrimary:#333333,textSecondary:#666666,textHint:#999999,primary:#FF6B6B,primaryLight:#FFE5E5,success:#4CAF50,warning:#FF9800,border:#E0E0E0,divider:#EEEEEE};2.4 深色主题配置constDarkTheme:ThemeColors{background:#1A1A1A,cardBackground:#2D2D2D,textPrimary:#FFFFFF,textSecondary:#B0B0B0,textHint:#808080,primary:#FF6B6B,primaryLight:#3D2D2D,success:#66BB6A,warning:#FFB74D,border:#404040,divider:#333333};三、ThemeUtil工具类实现3.1 类结构设计┌─────────────────────────────────────┐ │ ThemeUtil │ ├─────────────────────────────────────┤ │ - instance: ThemeUtil │ │ - currentTheme: ThemeColors │ │ - isDarkMode: boolean │ ├─────────────────────────────────────┤ │ getInstance(): ThemeUtil │ │ updateTheme(config): void │ │ getColors(): ThemeColors │ │ isDark(): boolean │ │ getBackgroundColor(): string │ │ getCardBackground(): string │ │ getTextPrimary(): string │ │ ...其他getter方法 │ └─────────────────────────────────────┘3.2 完整实现代码importConfigurationConstantfromohos.app.ability.ConfigurationConstant;import{Configuration}fromkit.AbilityKit;// 主题颜色接口同上exportinterfaceThemeColors{...}// 主题配置同上constLightTheme:ThemeColors{...};constDarkTheme:ThemeColors{...};exportclassThemeUtil{privatestaticinstance:ThemeUtil|nullnull;privatecurrentTheme:ThemeColorsLightTheme;privateisDarkMode:booleanfalse;// 私有构造函数privateconstructor(){}// 获取单例publicstaticgetInstance():ThemeUtil{if(!ThemeUtil.instance){ThemeUtil.instancenewThemeUtil();}returnThemeUtil.instance;}/** * 根据配置更新主题 */publicupdateTheme(configuration:Configuration):void{try{constcolorModeconfiguration.colorMode;this.isDarkModecolorModeConfigurationConstant.ColorMode.COLOR_MODE_DARK;this.currentThemethis.isDarkMode?DarkTheme:LightTheme;console.info([ThemeUtil] 主题已更新:${this.isDarkMode?深色:浅色});}catch(err){consterrorMsgerrinstanceofError?err.message:String(err);console.error([ThemeUtil] 更新主题失败:${errorMsg});}}/** * 获取当前主题颜色 */publicgetColors():ThemeColors{returnthis.currentTheme;}/** * 是否深色模式 */publicisDark():boolean{returnthis.isDarkMode;}// 其他getter方法...publicgetBackgroundColor():string{returnthis.currentTheme.background;}publicgetCardBackground():string{returnthis.currentTheme.cardBackground;}publicgetTextPrimary():string{returnthis.currentTheme.textPrimary;}publicgetTextSecondary():string{returnthis.currentTheme.textSecondary;}publicgetTextHint():string{returnthis.currentTheme.textHint;}publicgetPrimary():string{returnthis.currentTheme.primary;}publicgetSuccess():string{returnthis.currentTheme.success;}publicgetBorder():string{returnthis.currentTheme.border;}}四、Ability中监听主题变化4.1 在EntryAbility中添加监听import{AbilityConstant,ConfigurationConstant,UIAbility,Want,Configuration}fromkit.AbilityKit;import{ThemeUtil}from../utils/ThemeUtil;exportdefaultclassEntryAbilityextendsUIAbility{onCreate(want:Want,launchParam:AbilityConstant.LaunchParam):void{// 设置跟随系统主题try{this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);}catch(err){hilog.error(DOMAIN,testTag,Failed to set colorMode);}}/** * 监听系统配置变化包括主题变化 */onConfigurationUpdate(newConfig:Configuration):void{hilog.info(DOMAIN,testTag,Configuration updated);// 更新主题try{ThemeUtil.getInstance().updateTheme(newConfig);}catch(err){hilog.error(DOMAIN,testTag,Failed to update theme);}}}4.2 配置变化流程【图2主题切换流程】┌─────────────────────────────────────┐ │ 主题切换流程 │ ├─────────────────────────────────────┤ │ 用户切换系统主题 │ │ ↓ │ │ 系统发送Configuration变化事件 │ │ ↓ │ │ EntryAbility.onConfigurationUpdate │ │ ↓ │ │ ThemeUtil.updateTheme() │ │ ↓ │ │ 更新currentTheme和isDarkMode │ │ ↓ │ │ UI组件响应式更新 │ └─────────────────────────────────────┘五、页面中使用主题5.1 定义主题状态变量import{ThemeUtil,ThemeColors}from../utils/ThemeUtil;EntryComponentstruct PomodoroPage{// 主题状态StatethemeColors:ThemeColorsThemeUtil.getInstance().getColors();StateisDarkMode:booleanfalse;// 工具类privatethemeUtil:ThemeUtilThemeUtil.getInstance();// 生命周期asyncaboutToAppear(){// 初始化主题this.themeColorsthis.themeUtil.getColors();this.isDarkModethis.themeUtil.isDark();}}5.2 在UI组件中应用主题颜色BuilderTopBar(){Row(){Text( 番茄钟).fontSize(24).fontWeight(FontWeight.Bold).fontColor(#FFFFFF)}.width(100%).height(56).backgroundColor(this.isBreak?this.themeColors.success:this.themeColors.primary)}BuilderTimerSection(){Column(){// 进度条Progress({value:this.getProgress(),total:100,type:ProgressType.Ring}).color(this.isBreak?this.themeColors.success:this.themeColors.primary).backgroundColor(this.themeColors.border)// 时间显示Text(this.formatTime(this.timeLeft)).fontSize(64).fontWeight(FontWeight.Bold).fontColor(this.themeColors.textPrimary)}.width(100%).backgroundColor(this.themeColors.background)}BuilderPomodoroStats(){Column(){Row(){Column(){Text(this.pomodoroCount.toString()).fontSize(28).fontWeight(FontWeight.Bold).fontColor(this.themeColors.primary)Text(今日完成).fontSize(12).fontColor(this.themeColors.textSecondary)}}}.backgroundColor(this.themeColors.cardBackground)}5.3 半模态弹窗主题适配.bindSheet($$this.showTimePicker,this.TimePickerSheet(),{height:300,backgroundColor:this.isDarkMode?#2D2D2D:Color.White,dragBar:true,onWillDismiss:(){this.showTimePickerfalse;}})六、颜色对比效果6.1 浅色主题效果【图3浅色主题】6.2 深色主题效果【图4深色主题】七、最佳实践7.1 颜色使用规范// ✅ 推荐使用主题颜色.backgroundColor(this.themeColors.background).fontColor(this.themeColors.textPrimary)// ❌ 不推荐硬编码颜色.backgroundColor(#F5F5F5).fontColor(#333333)7.2 状态变量设计// ✅ 推荐使用State自动响应StatethemeColors:ThemeColorsThemeUtil.getInstance().getColors();// ❌ 不推荐普通变量不会触发更新privatethemeColors:ThemeColorsThemeUtil.getInstance().getColors();7.3 主题颜色扩展// 扩展主题颜色接口exportinterfaceThemeColors{// 基础颜色...// 扩展颜色error:string;// 错误色info:string;// 信息色disabled:string;// 禁用色}// 在主题配置中添加constLightTheme:ThemeColors{// 基础颜色...error:#F44336,info:#2196F3,disabled:#BDBDBD};八、总结本文实现了番茄钟应用的深浅色主题适配颜色体系设计定义完整的ThemeColors接口工具类封装ThemeUtil单例类管理主题状态系统监听在Ability中监听配置变化响应式更新使用State实现UI自动更新主题适配是现代应用的基本要求合理的设计可以让应用在各种环境下都有良好的显示效果。