尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

【时光清单|07】HarmonyOS ArkTS 主题系统实战:集中管理亮暗色和语义颜色

发布时间:2026/9/2 8:38:26

资讯中心
01
ARTICLE

【时光清单|07】HarmonyOS ArkTS 主题系统实战:集中管理亮暗色和语义颜色

【时光清单|07】HarmonyOS ArkTS 主题系统实战:集中管理亮暗色和语义颜色
【时光清单07】HarmonyOS ArkTS 主题系统实战集中管理亮暗色和语义颜色HarmonyOS 应用的主题系统不是“准备几组背景色”这么简单。用户选择一种视觉主题后页面背景、卡片、主色、正文、次要文字和系统栏必须一起变化系统从亮色切到暗色时当前主题仍要保留只切换到对应的暗色令牌。如果每个页面自己判断isDark、自己拼十六进制颜色最终一定会出现遗漏主体已经变暗弹窗仍是白色页面背景已切换状态栏图标却看不清某个主题有暗色主色另一个页面仍使用亮色常量。时光清单的真实源码把主题模型定义在Theme.ets由AppStore.applyTheme()根据主题 ID 和当前颜色模式解析语义色再写入AppStorage。页面使用StorageLink(StateKeys.THEME_BG)等键响应变化EntryAbility.onConfigurationUpdate()监听系统颜色模式并重新应用当前主题。项目里还存在ThemeManager与ThemeService两个并行抽象但主要页面实际调用的是AppStore这一点必须先辨清。本文沿真实调用链拆解主题定义、亮暗色解析、系统配置监听、状态栏适配、时间氛围背景与主题选择页面同时指出当前语义色覆盖不完整、主题持久化尚未真正接通以及多套主题入口并存的工程风险。本文将完成这些源码复核说明AppTheme为什么同时保存亮色与暗色令牌。还原主题选择到所有页面刷新的真实链路。分析系统深色模式变化如何重新解析当前主题。解释状态栏内容色为什么要跟随背景亮度。区分当前生效的AppStore与并存的ThemeManager、ThemeService。给出语义色、持久化、对比度和多设备测试的渐进改造方案。本文唯一标记CSDN-SERIES:ALL-163203514证据边界当前源码、历史记录与建议实现本文的当前事实来自主题模型、AppStore、状态键、主题页面、入口 Ability、亮暗资源文件以及定向引用搜索。静态源码可以证明字段、调用关系和未接通的分支但不能单独证明所有页面在真机上都可读也不能证明每套颜色已通过对比度检测。本轮没有运行构建、设备或截图回归所以不会补写这些结果。历史部分只引用项目PROJECT_ERRORS.md的明确记录。该记录写明 2026 年 5 月 20 日曾出现“深夜星空主题导致全部 Tab 页字体看不清”并记录了根因、修复和当时的assembleHap成功。那是历史证据不等于本轮重新构建通过。下文带“建议”“应当”的方案同样不代表已经实现。一、主题系统首先解决“语义”不是色值页面通常不应该关心当前主题的背景到底是#F5F0E8还是#121212。页面只需要表达“这里是页面背景”“这里是卡片表面”“这里是主要文字”。具体色值由主题解析层决定。时光清单的AppTheme定义了主题身份和语义角色export type ThemeId chinese_ink | sunset | minimal_white | starry_night | sakura; export interface AppTheme { id: ThemeId; name: string; primaryColor: string; secondaryColor: string; backgroundColor: string; cardColor: string; textPrimary: string; textSecondary: string; backgroundImage?: string; darkPrimaryColor: string; darkBackgroundColor: string; darkCardColor: string; }这些字段不是随意的一组颜色而是设计令牌令牌页面语义亮色示例暗色示例primaryColor品牌、选中、强调国风蓝提亮后的蓝backgroundColor页面底色米白深蓝黑cardColor卡片和表面白色深灰蓝textPrimary标题、正文深色当前由解析层统一浅色textSecondary辅助信息中灰当前由解析层统一浅灰页面消费“角色”而不是“主题名字”才能让五套主题和两种颜色模式组合成十种状态而不把条件分支复制到每个组件。二、五套真实主题如何组织源码中的THEMES包含国风山水、治愈日落、极简白、深夜星空和樱花树export const THEMES: AppTheme[] [ { id: chinese_ink, name: 国风山水, primaryColor: #2C5F7C, backgroundColor: #F5F0E8, cardColor: #FFFFFF, textPrimary: #1A1A1A, textSecondary: #666666, darkPrimaryColor: #6C8EBF, darkBackgroundColor: #1A1A2E, darkCardColor: #2D2D44 }, { id: minimal_white, name: 极简白, primaryColor: #333333, backgroundColor: #FFFFFF, cardColor: #F8F8F8, darkPrimaryColor: #E0E0E0, darkBackgroundColor: #121212, darkCardColor: #1E1E1E } ];每套主题都必须提供同一组必填字段。这样getThemeById()不需要知道主题细节export function getThemeById(id: ThemeId): AppTheme { return THEMES.find( (t: AppTheme) t.id id ) ?? THEMES[0]; }未知 ID 会降级到第一套主题避免配置迁移或非法输入导致页面没有颜色。不过降级只是运行时保护持久化恢复时仍应验证旧值必要时记录迁移而不是长期静默掩盖错误。三、当前真正生效的入口是 AppStore项目虽然有ThemeManager和ThemeService但从页面引用关系看主题设置页直接调用.onClick(() { this.selectedTheme theme.id; AppStore.applyTheme(theme.id); })AppStore.applyTheme()是当前主要解析器static applyTheme(themeId: ThemeId): void { const theme getThemeById(themeId); const isDark AppStorage.getboolean(StateKeys.DARK_MODE) ?? false; const bg isDark ? theme.darkBackgroundColor : theme.backgroundColor; const card isDark ? theme.darkCardColor : theme.cardColor; const primary isDark ? theme.darkPrimaryColor : theme.primaryColor; const textPrimary isDark ? #E8E8F0 : theme.textPrimary; const textSecondary isDark ? #D0D0E4 : theme.textSecondary; AppStore.setStorageString( StateKeys.CURRENT_THEME, themeId ); AppStore.setStorageString(StateKeys.THEME_BG, bg); AppStore.setStorageString(StateKeys.THEME_CARD, card); AppStore.setStorageString( StateKeys.THEME_PRIMARY, primary ); AppStore.setStorageString( StateKeys.THEME_TEXT_PRIMARY, textPrimary ); AppStore.setStorageString( StateKeys.THEME_TEXT_SECONDARY, textSecondary ); AppStore.updateStatusBarStyle(bg); }输入只有两个themeId和isDark。输出是一组已经解析好的语义颜色。页面不再执行亮暗色分支这是集中主题系统最核心的价值。四、用 AppStorage 把解析结果广播到页面StateKeys给主题值定义统一键名static readonly DARK_MODE: string isDarkMode; static readonly CURRENT_THEME: string currentThemeId; static readonly THEME_BG: string themeBgColor; static readonly THEME_CARD: string themeCardColor; static readonly THEME_PRIMARY: string themePrimaryColor; static readonly THEME_TEXT_PRIMARY: string themeTextPrimary; static readonly THEME_TEXT_SECONDARY: string themeTextSecondary;首页、全部列表、详情页、日记、相册、习惯、心愿等页面都订阅THEME_BGStorageLink(StateKeys.THEME_BG) themeBg: string #F5F0E8; build() { Column() { // 页面内容 } .width(100%) .height(100%) .backgroundColor(this.themeBg); }主题设置页还订阅当前主题StorageLink(StateKeys.CURRENT_THEME) currentThemeId: string chinese_ink; State selectedTheme: ThemeId chinese_ink; aboutToAppear(): void { this.selectedTheme this.currentThemeId as ThemeId; }用户点击主题后AppStore更新多个 AppStorage 键所有仍在组件树中的页面都能响应。平板或 2in1 双栏布局可能同时显示导航与内容页面这种广播比“返回页面时再读取设置”更可靠。五、启动链路默认主题、窗口与系统栏EntryAbility.onCreate()调用AppStore.bootstrap()AppStore.bootstrap(this.context); DataStore.getInstance().init(this.context); this.hydratePersistentState();bootstrap()初始化颜色模式、当前主题和各类运行时状态然后应用默认国风主题AppStorage.setOrCreateboolean( StateKeys.DARK_MODE, isDark ); AppStorage.setOrCreatestring( StateKeys.CURRENT_THEME, chinese_ink ); AppStore.applyTheme(chinese_ink);窗口创建后应用保存主窗口引用并再次使用当前主题更新系统栏const win windowStage.getMainWindowSync(); AppStore.setMainWindow(win); const themeId ( AppStorage.getstring( StateKeys.CURRENT_THEME ) ?? chinese_ink ) as ThemeId; AppStore.applyTheme(themeId);第二次应用不是简单重复。bootstrap()执行时主窗口可能尚未建立无法设置状态栏内容色窗口创建后重新应用才能让系统栏与页面背景保持一致。六、系统颜色模式变化如何进入主题系统EntryAbility.onConfigurationUpdate()监听系统配置onConfigurationUpdate( newConfig: Configuration ): void { const isDark newConfig.colorMode ConfigurationConstant.ColorMode.COLOR_MODE_DARK; const currentDark AppStorage.getboolean( StateKeys.DARK_MODE ) ?? false; if (isDark ! currentDark) { AppStore.onDarkModeChanged(isDark); } }onDarkModeChanged()不改变主题 ID而是更新模式后重新应用当前主题static onDarkModeChanged(isDark: boolean): void { AppStorage.setboolean( StateKeys.DARK_MODE, isDark ); const themeId ( AppStorage.getstring( StateKeys.CURRENT_THEME ) ?? chinese_ink ) as ThemeId; AppStore.applyTheme(themeId); }因此用户选择“樱花树”后切换系统暗色仍然是樱花主题只是背景、卡片和主色切换到该主题的暗色令牌。主题身份和颜色模式是两个独立维度ThemeId: sakura ColorMode: light - sakura.backgroundColor - sakura.cardColor - sakura.primaryColor ThemeId: sakura ColorMode: dark - sakura.darkBackgroundColor - sakura.darkCardColor - sakura.darkPrimaryColor七、应用内手动切换亮暗色个人页提供亮色和暗色模式按钮最终调用static applyColorMode(dark: boolean): void { if (AppStore.appContext null) return; try { const mode: ConfigurationConstant.ColorMode dark ? ConfigurationConstant.ColorMode .COLOR_MODE_DARK : ConfigurationConstant.ColorMode .COLOR_MODE_LIGHT; AppStore.appContext.setColorMode(mode); AppStore.onDarkModeChanged(dark); } catch (_e) {} }这里既调用应用级setColorMode()又立即更新本地状态。用户不必等待配置回调才看到变化。当前界面实际显示“跟随系统”“浅色”“深色”三个标签但ModeChip点击处理只实现了dark和light两个分支auto没有执行动作。bootstrap()会调用COLOR_MODE_NOT_SET让默认启动行为跟随系统用户一旦手动固定模式现有“跟随系统”标签并不能把应用重置为系统模式。这里需要补齐第三种偏好和值到平台模式的映射而不是继续用一个布尔变量表达三态。更完整的模型应是export type ColorModePreference system | light | dark;DARK_MODE表示当前实际模式COLOR_MODE_PREFERENCE表示用户偏好两者不能混为一谈。八、系统栏内容色背景变化后的最后一步沉浸式布局把页面背景延伸到状态栏区域。如果背景变暗而状态栏仍显示黑色图标时间、电量和网络状态会失去可读性。源码通过背景亮度估算内容色private static isLightColor(hex: string): boolean { const c hex.replace(#, ); const r parseInt(c.substring(0, 2), 16); const g parseInt(c.substring(2, 4), 16); const b parseInt(c.substring(4, 6), 16); return ( r * 0.299 g * 0.587 b * 0.114 ) 128; }然后同步状态栏与导航栏图标颜色const contentColor isLight ? #000000 : #FFFFFF; AppStore.mainWindow .setWindowSystemBarProperties({ statusBarContentColor: contentColor, navigationBarContentColor: contentColor });这是一种实用的二值判断但只接受六位十六进制颜色。若未来加入八位透明色、资源引用、渐变或背景图片解析函数就不能准确代表实际背景。更稳妥的做法是在主题模型里直接声明系统栏内容风格interface SystemBarTokens { lightContent: boolean; navigationBarColor: string; }设计令牌比运行时猜测更可控尤其是在复杂背景和图片主题中。九、语义色覆盖还不完整AppStore已经广播背景、卡片、主色、主要文字和次要文字但主题设置页仍大量使用静态AppColorsText(theme.name) .fontColor(AppColors.textPrimary) Text(this.getThemeDesc(theme.id)) .fontColor(AppColors.textTertiary) .backgroundColor(AppColors.bgSurface)这说明当前主题系统处于“动态页面背景已经接通组件内部语义色仍部分静态”的阶段。换主题时背景会变化但卡片文字、表面色和部分强调色未必完全跟随。修复方向不是在页面里增加更多isDark ? ... : ...而是让页面订阅完整令牌StorageLink(StateKeys.THEME_CARD) themeCard: string #FFFFFF; StorageLink(StateKeys.THEME_PRIMARY) themePrimary: string #2C5F7C; StorageLink(StateKeys.THEME_TEXT_PRIMARY) themeTextPrimary: string #1A1A1A; StorageLink(StateKeys.THEME_TEXT_SECONDARY) themeTextSecondary: string #666666;随后将可变主题色从静态AppColors替换为对应语义状态。固定的错误色、警告色和成功色也应单独设计不应直接复用品牌主色。十、ThemeManager 与 ThemeService 的真实边界ThemeManager是Observed单例Observed export class ThemeManager { private static instance: ThemeManager | null null; currentTheme: AppTheme THEMES[0]; switchTheme(id: ThemeId): void { this.currentTheme getThemeById(id); AppStorage.setOrCreate( currentThemeId, id ); } }ThemeService则只在静态字段中保存当前 IDexport class ThemeService { private static currentThemeId: ThemeId chinese_ink; static setTheme(id: ThemeId): void { ThemeService.currentThemeId id; } static getTheme(): AppTheme { return getThemeById( ThemeService.currentThemeId ); } }两者还都提供按小时计算氛围背景的能力。然而从项目引用看主题设置和颜色模式实际由AppStore驱动主要页面也没有订阅ThemeManager.currentTheme或读取ThemeService.getTheme()。因此不能把三套机制描述成一个已统一系统。更准确的结论是抽象当前能力主链路状态AppStore解析亮暗色、广播语义色、更新系统栏当前生效ThemeManager观察对象、切换主题、自动背景并存主要页面未采用ThemeService静态主题 ID、氛围背景映射并存主要页面未采用工程上应该保留一个主题写入口。若确认AppStore是正式方案就把自动背景能力迁入专门的MoodService逐步删除或停止扩展另外两套主题状态避免出现三个“当前主题”。十一、时间氛围背景是第二个维度getMoodToneByHour()将小时映射为四个时段export function getMoodToneByHour( hour: number ): MoodTone { if (hour 5 hour 9) return morning; if (hour 9 hour 16) return noon; if (hour 16 hour 19) return dusk; return night; }ThemeService.getMoodBackground()再映射资源名static getMoodBackground( tone: MoodTone ): string { switch (tone) { case morning: return bg_hero_mountain; case noon: return bg_card_salary; case dusk: return bg_card_couple; case night: return bg_card_quote; case rain: case snow: return bg_card_countdown; } }主题解决颜色语言氛围背景解决内容场景。两者可以组合但不应该互相覆盖主题决定背景底色、卡片、文字与强调色 氛围决定可选背景图片 颜色模式决定亮色令牌或暗色令牌背景图片必须有遮罩或文字保护策略。不能因为图片“看起来好看”就让正文对比度随时段和素材明暗随机变化。十二、当前主题并未真正持久化StateKeys注释提到AppStorage / PersistentStorage但源码搜索不到把CURRENT_THEME连接到PersistentStorage的实际调用EntryAbility.hydratePersistentState()当前只恢复MOOD_BACKGROUND。同时bootstrap()每次启动都执行AppStore.applyTheme(chinese_ink);这意味着本次运行内切换主题有效但从当前可见源码不能确认主题选择会跨启动保存。文章不能把“写入 AppStorage”误写为“完成持久化”。若要跨启动保留主题可沿项目现有DataStore模式实现interface AppearancePreference { themeId: ThemeId; colorMode: ColorModePreference; moodBackground: string; }启动时先同步读取偏好再初始化 AppStorage 和应用主题切换主题时先保存偏好成功后广播新令牌。还要考虑旧版本没有字段、主题 ID 已移除和非法值降级。十三、主题切换的正确时序完整时序应保持单向用户选择主题 - 校验 ThemeId - 保存用户偏好若支持跨启动 - 读取当前实际颜色模式 - 解析一组完整语义令牌 - 原子式更新主题状态 - 页面响应 - 更新状态栏与导航栏当前AppStore逐个写 AppStorage 键。ArkUI 更新通常足够快但理论上组件可能短暂观察到新背景与旧文字。若主题规模扩大可把令牌封装为一个对象interface ResolvedThemeTokens { id: ThemeId; dark: boolean; background: string; surface: string; primary: string; textPrimary: string; textSecondary: string; }页面订阅一个完整快照可以减少中间状态。不过 ArkTS 和 ArkUI 对复杂对象观察方式有明确要求改造前应结合现有状态模型验证不能只照搬 Web 状态管理习惯。十四、颜色对比度是发布门槛主题越多组合测试越容易漏。AppGallery 审核关注关键文字、图标、按钮和正文的可读性。工程上至少采用以下目标正文与背景对比度不低于4.5:1。大号文字、图标和关键操作与背景对比度高于3:1。禁用态仍可识别但不能与正常态混淆。选中不能只依赖颜色还要有边框、图标或文案。当前主题选择页用三段色块预览主色、背景和卡片色这是很好的快速识别方式选中项还显示“✓ 使用中”并增加边框不只依赖色差。但暗色预览尚未展示。更完善的预览可以在每个主题卡中同时显示亮、暗两组迷你色板或者让预览跟随当前模式避免用户在亮色环境选择主题后进入暗色才发现效果不合适。十五、不要忘记图标、弹窗和系统区域主题测试不能只看页面根背景。每套主题都要覆盖状态栏和导航栏。底部导航选中与未选中态。卡片、列表项、分割线和阴影。对话框、底部弹窗和 Toast。输入框、占位符、光标与错误提示。空状态、加载态、失败态和禁用态。图片上的文字与半透明遮罩。可染色图标和不可染色位图。如果图标本身是深灰色 PNG切到深色卡片后可能消失。可染色资源应使用统一 tint 令牌必须保留原色的位图则要准备适配版本或稳定的承载底色。十六、多设备与窗口变化测试手机上主题切换通常只有一个页面可见平板和 2in1 可能同时存在侧栏、列表和详情。所有区域必须订阅同一主题令牌不能只有新打开页面使用新主题。建议覆盖手机竖屏 五套主题 × 亮色/暗色 手机横屏/小窗口 长标题、底部安全区、弹窗 平板 双栏同时切换不出现一明一暗 2in1 调整窗口尺寸后主题与系统栏不丢失 系统动态切换 应用前台、后台恢复、配置更新还要测试切换时页面是否闪白。首帧先显示默认主题、异步读取偏好后再切换会产生明显闪烁。EntryAbility已经对心情背景采用同步初始化这一思路也适用于外观偏好在加载页面内容之前取得最小主题配置。十七、异常与降级策略主题系统不应因一个非法颜色让应用崩溃。建议定义清晰降级异常降级未知主题 ID回退chinese_ink非法颜色字符串使用默认语义令牌状态栏更新失败记录日志页面继续显示背景图片缺失使用纯色背景偏好读取失败默认跟随系统主题保存失败保持旧主题并提示当前updateStatusBarStyle()已通过try/catch避免窗口 API 失败影响页面符合“装饰能力失败不阻断核心流程”的原则。但空catch不应遍布主题主链路至少需要可诊断日志。十八、渐进式整理方案结合现有源码最稳妥的改造顺序是明确AppStore为唯一主题写入口。将页面中可变的AppColors替换为动态语义令牌。新增ColorModePreference支持系统、亮色、暗色三态。使用现有DataStore持久化主题与颜色模式偏好。启动时同步恢复偏好避免首帧闪烁。将自动背景逻辑迁到独立MoodService。清理未使用的ThemeManager、ThemeService或ThemeConfig重复职责。为每套主题建立对比度与多设备截图基线。每一步都应保持ThemeId - Resolved Tokens - Page这条单向链路不让页面重新成为颜色决策者。十九、可复核测试清单模型层五个合法 ID 都能解析。非法 ID 回退第一套主题。每套主题亮暗色必填字段完整。getMoodToneByHour()覆盖 5、9、16、19 点边界。状态层切换主题后所有语义键更新。深色切换保持当前主题 ID。同一主题重复应用不会产生异常。主窗口存在时系统栏内容色同步。主窗口不存在时不阻断启动。页面层主题设置页选中标记正确。所有存活页面同步刷新。长文案和列表滚动不受颜色切换影响。错误、空状态和禁用态可读。背景图片加载失败时仍有纯色底。发布层五套主题在亮暗模式下通过对比度检查。状态栏、导航栏与页面背景一致。手机、平板、2in1 不出现局部旧主题。重启后的外观行为与设置文案一致。隐私说明不虚构联网或云端主题能力。二十、历史问题为什么值得保留为回归样例项目记录中的深夜星空问题不是抽象风险而是主题系统最典型的失配页面背景和主色已经切换Tab 外壳却没有消费同一组文字令牌同时旧实现用setOrCreate写已存在的 AppStorage 键导致新主题值可能没有覆盖旧值。记录中的修复把深夜星空普通模式调整为浅色可读背景改为显式覆盖动态令牌并让未选中 Tab 使用主题次级文字色。这段历史说明主题验收不能只看设置页预览。设置页色块正确不代表 Tab、列表、弹窗和系统栏都消费了同一真源。建议把该问题固化为回归样例选择深夜星空遍历所有 Tab核对背景、主要文字、次要文字、未选中状态和系统栏再切到暗色并重复一次。历史构建成功只能证明当时编译完成不能替代今天的视觉回归。二十一、建议用完整快照收敛双轨颜色这一节全部是建议实现。当前工程一边通过AppTheme和 AppStorage 传播字符串色一边通过AppColors读取 base/dark 资源色。两套机制各自合理但同时成为页面颜色来源时容易漂移。建议先定义用户偏好与实际模式的区别export type ColorModePreference system | light | dark; export interface ThemePreference { themeId: ThemeId; colorMode: ColorModePreference; }ThemePreference适合持久化实际isDark则由系统配置和偏好共同计算。选择 system 时必须调用平台的COLOR_MODE_NOT_SET不能只把本地布尔值改回浅色。建议将映射集中在唯一入口function resolvePlatformMode(pref: ColorModePreference): ConfigurationConstant.ColorMode { if (pref light) return ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT; if (pref dark) return ConfigurationConstant.ColorMode.COLOR_MODE_DARK; return ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET; }随后把一次主题解析的全部结果放进不可分割的快照。页面不应在背景用动态字符串、正文用资源色、边框又写硬编码值而应消费同一快照中的语义角色export interface ThemeSnapshot { page: string; surface: string; surfaceAlt: string; primary: string; textPrimary: string; textSecondary: string; border: string; divider: string; systemBarContent: string; }快照字段必须覆盖真实页面需要的语义而不是为了示例虚构无限令牌。错误、警告、成功、禁用、按下和选中态是否随主题变化要由产品设计决定。若资源限定目录继续承担亮暗适配可以由一个适配层读取资源并构造快照若五套主题必须动态变化则应从统一定义生成字符串快照与资源配置避免人工维护两份不一致的颜色表。持久化也需要明确顺序。当前源码没有把CURRENT_THEME写入DataStore因此建议先同步读取最小偏好再创建页面读取失败时回退国风山水和系统模式非法 ID 则通过getThemeById的受控降级处理const preference loadThemePreferenceSync(); applyPlatformMode(preference.colorMode); const snapshot resolveTheme(preference.themeId, currentSystemMode()); publishThemeSnapshot(snapshot);这只是时序示意函数尚未存在。真正实现要避免启动阶段先发布默认主题、随后异步切换造成闪白也要在保存失败时保持旧偏好并给出可诊断结果。主题设置页预览还应根据当前实际模式选择darkPrimaryColor、darkBackgroundColor和darkCardColor不能始终展示亮色字段。最后对比度检查应该针对语义组合而不是孤立色值。建议生成主题与模式笛卡尔积至少覆盖五套主题的亮暗两态for (const theme of THEMES) { verifyContrast(resolveTheme(theme.id, false)); verifyContrast(resolveTheme(theme.id, true)); }verifyContrast仍是建议测试辅助函数。它应检查正文、次要文字、按钮、图标、边框、禁用态和系统栏的真实前景/背景组合并结合页面截图处理背景图片、透明层和渐变等纯色公式无法判断的情况。二十二、总结时光清单当前主题主链路可以概括为Theme.ets 定义主题原始令牌 - AppStore 结合 DARK_MODE 解析 - AppStorage 广播语义颜色 - 页面 StorageLink 响应 - 主窗口同步系统栏内容色这套结构已经解决了主题 ID 与颜色模式分离、页面背景集中更新、系统配置变化和状态栏可读性等关键问题。源码同时暴露出三个值得继续收敛的边界组件内部仍有静态颜色、主题偏好尚未从可见代码中接入跨启动持久化、ThemeManager与ThemeService和AppStore存在职责重叠。主题系统的验收标准不是“能切换五种颜色”而是任何主题与颜色模式组合下语义一致、内容可读、系统区域协调多页面只存在一个当前主题真源。本文基于时光清单项目的Theme.ets、ThemeManager.ets、ThemeService.ets、AppStore.ets、EntryAbility.ets和主题设置页面真实源码复核整理。文中明确区分了当前已接入链路与建议改造未将未使用抽象描述为已生效能力。AI 辅助声明本文在真实源码核验、结构梳理和文字编辑过程中使用了 AI 辅助关键接口、引用关系和工程结论均以项目源码为依据进行人工复核。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。