【OpenHarmony/HarmonyOs 】49|资源化颜色主题:从硬编码色值到深色模式自动适配 🎨
本文基于当前项目
resources/base/element/color.json、resources/dark/element/color.json、LoginPage.ets、MainPage.ets、MoodPage.ets与ChatDetailPage.ets的真实实现展开。
项目已经为启动窗口准备了明暗资源,但业务页面仍存在大量十六进制与 rgba 硬编码;本文给出不破坏现有主题切换功能的渐进式资源化方案。
一、为什么颜色资源化不是简单的字符串替换?
当前项目同时存在三类颜色来源:
- 启动窗口使用
$color:start_window_background; - 页面使用
readonly primaryColor: string = '#009688'; - 聊天详情使用
ChatTheme保存多套业务主题。
三者分别对应系统资源、页面常量与用户可选主题。
如果把所有色值一次性替换成同一个资源,会破坏聊天主题;如果只处理背景色,又可能让深色模式下文字失去对比度。
正确目标不是“代码里看不到 #”,而是建立清晰的颜色语义、资源覆盖关系与主题边界。
二、项目当前的真实资源基础
基础资源只有启动背景:
{ "color": [ {"name":"start_window_background","value":"#FFFFFF"} ] }深色目录使用相同资源名提供覆盖值:
{ "color": [ {"name":"start_window_background","value":"#000000"} ] }这已经证明项目具备资源限定目录的正确入口。
真正缺失的是业务语义色:页面背景、卡片背景、主要文字、次要文字、分割线、品牌色、危险色与遮罩色。
三、硬编码颜色带来的真实问题
LoginPage、MainPage和MoodPage都直接声明了薄荷主题色。
readonlyprimaryColor:string='#009688';readonlybgColor:string='#F5F7FA';readonlytextColor:string='#37474F';这种写法在浅色模式下直观,但系统切换深色模式时不会自动变化。
更隐蔽的问题是半透明白色卡片:
.backgroundColor('rgba(255, 255, 255, 0.7)')深色背景上继续叠加白色玻璃层,会产生突兀亮块。
因此迁移必须同时覆盖实体色、透明色、阴影色与状态色。
四、先建立语义色,而不是按色值命名
不推荐以下命名:
white;gray_100;teal_500;color_01。
推荐以下命名:
page_background;surface_primary;surface_secondary;text_primary;text_secondary;divider_color;brand_primary;danger_color。
语义命名表达“颜色负责什么”,而不是“颜色现在长什么样”。
五、推荐的基础资源结构
浅色资源可以扩展为:
{"color": [ {"name":"start_window_background","value":"#FFFFFF"}, {"name":"page_background","value":"#F5F7FA"}, {"name":"surface_primary","value":"#FFFFFF"}, {"name":"surface_secondary","value":"#E0F2F1"}, {"name":"text_primary","value":"#37474F"}, {"name":"text_secondary","value":"#78909C"}, {"name":"brand_primary","value":"#009688"}, {"name":"divider_color","value":"#EEEEEE"}, {"name":"danger_color","value":"#FF7043"} ] }深色资源保持同名,只替换值:
{"color": [ {"name":"start_window_background","value":"#000000"}, {"name":"page_background","value":"#101414"}, {"name":"surface_primary","value":"#1A2222"}, {"name":"surface_secondary","value":"#203634"}, {"name":"text_primary","value":"#E8F0EF"}, {"name":"text_secondary","value":"#A7B8B6"}, {"name":"brand_primary","value":"#4DB6AC"}, {"name":"divider_color","value":"#33403F"}, {"name":"danger_color","value":"#FF8A65"} ] }系统会根据当前颜色模式解析同名资源,页面不需要手写模式判断。
六、ArkUI 页面如何引用颜色资源?
组件属性直接使用$r:
.backgroundColor($r('app.color.page_background')) .fontColor($r('app.color.text_primary')) .border({ width:1, color:$r('app.color.divider_color')})当属性接受ResourceColor时,应优先保留资源对象,不要提前转为字符串。
错误做法是读取资源后拼接透明度字符串,因为这会重新退化为运行时色值处理。
七、颜色类型要跟着资源化调整
项目中的ChatTheme.headerBg已经使用:
headerBg:string| Resource;但其他字段仍是string。
如果主题字段允许资源,应统一考虑ResourceColor或项目当前 API 支持的兼容类型。
不要在调用处大量使用as string,否则类型声明虽然支持资源,实际代码仍强迫它成为字符串。
八、系统深色模式与聊天业务主题不是一回事
系统模式回答:当前环境适合浅色还是深色。
聊天主题回答:用户想使用薄荷、暖色还是粉色。
推荐分层:
- 系统资源提供基础页面、文字、边框和遮罩;
- 聊天主题只覆盖头部、气泡、发送按钮等品牌化区域;
- 每套聊天主题都需要浅色与深色可读性验证;
- 未被业务主题覆盖的区域继续使用系统语义资源。
这样既保留现有换肤能力,又能响应系统颜色模式。
九、不要强制锁定颜色模式
EntryAbility当前调用:
this.context.getApplicationContext().setColorMode( ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET );COLOR_MODE_NOT_SET的方向是让应用遵循系统配置。
如果页面颜色仍全部硬编码,遵循系统也不会产生完整效果。
资源化迁移完成后,这个入口才能真正发挥作用。
十、渐进迁移顺序
建议按风险从低到高迁移:
- 页面大背景;
- 主次文字;
- 卡片与分割线;
- 普通按钮与图标;
- 阴影和半透明玻璃层;
- 聊天气泡与动态主题;
- 图表、热力图和渐变。
每完成一类都应在浅色、深色和高对比场景核验。
十一、资源化实施核验清单
检查项 1:资源命名
- 检查目标:颜色名表达页面语义。
- 常见反例:出现 white、gray 或 color01 等外观命名。
- 推荐动作:重命名为 page、surface、text、brand 等职责名称。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 2:同名覆盖
- 检查目标:base 与 dark 使用完全相同的资源名。
- 常见反例:深色目录另起一套 dark_xxx 名称。
- 推荐动作:让资源系统自动选择,不在页面判断模式。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 3:页面背景
- 检查目标:根容器使用 page_background。
- 常见反例:继续写死 #F5F7FA。
- 推荐动作:先迁移最稳定、覆盖面积最大的背景色。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 4:主要文字
- 检查目标:标题和正文使用 text_primary。
- 常见反例:深色模式仍显示 #37474F。
- 推荐动作:验证普通字号下的对比度。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 5:次要文字
- 检查目标:辅助信息使用 text_secondary。
- 常见反例:为了显得柔和而降低到不可读。
- 推荐动作:在真实设备与低亮度环境检查。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 6:卡片表面
- 检查目标:卡片使用 surface_primary。
- 常见反例:把所有白色都替换成同一背景色。
- 推荐动作:区分页面层与浮层层级。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 7:次级表面
- 检查目标:标签和选中态使用 surface_secondary。
- 常见反例:直接复用品牌色导致面积过重。
- 推荐动作:用柔和表面承载弱强调。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 8:分割线
- 检查目标:边界使用 divider_color。
- 常见反例:深色模式仍用 #EEEEEE。
- 推荐动作:控制边界可见但不过度抢眼。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 9:品牌色
- 检查目标:主要动作使用 brand_primary。
- 常见反例:每个页面复制 #009688。
- 推荐动作:统一品牌入口并允许深色提亮。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 10:危险色
- 检查目标:删除和失败状态使用 danger_color。
- 常见反例:把业务失败与普通品牌色混用。
- 推荐动作:保持跨页面状态语义一致。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 11:阴影色
- 检查目标:阴影资源按模式调整透明度。
- 常见反例:深色模式继续使用浅色外发光。
- 推荐动作:深色环境优先用层级与描边。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 12:遮罩色
- 检查目标:弹层遮罩拥有独立语义。
- 常见反例:把纯黑透明值散落各页面。
- 推荐动作:统一遮罩强度并验证可关闭区域。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 13:透明卡片
- 检查目标:玻璃层在两种模式都有资源方案。
- 常见反例:固定 rgba(255,255,255,0.7)。
- 推荐动作:深色模式改用深色半透明表面。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 14:渐变起点
- 检查目标:渐变端点由语义资源控制。
- 常见反例:组件内部直接写多个十六进制值。
- 推荐动作:明确渐变是品牌还是状态表达。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 15:图标颜色
- 检查目标:普通图标跟随 text_secondary。
- 常见反例:图标固定黑色或白色。
- 推荐动作:让图标与相邻文字保持同级。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 16:禁用状态
- 检查目标:禁用前景和背景分别定义。
- 常见反例:只通过 opacity 处理所有禁用效果。
- 推荐动作:检查文字仍然可读且状态明确。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 17:选中状态
- 检查目标:选中态使用品牌语义。
- 常见反例:仅靠颜色表达选中。
- 推荐动作:同时增加字重、图标或形状提示。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 18:焦点状态
- 检查目标:键盘焦点边框可见。
- 常见反例:深色主题下焦点环消失。
- 推荐动作:为焦点建立独立高对比资源。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 19:链接颜色
- 检查目标:链接与正文有稳定区分。
- 常见反例:链接直接复用浅色品牌值。
- 推荐动作:验证已访问、按压和禁用状态。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 20:输入框
- 检查目标:输入背景、文字、占位符分开定义。
- 常见反例:所有文字共用一个灰色。
- 推荐动作:保证输入内容优先级最高。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 21:错误输入
- 检查目标:错误边框与错误文案一致。
- 常见反例:只改变边框且无文字说明。
- 推荐动作:颜色之外提供明确错误描述。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 22:状态栏
- 检查目标:顶部区域与页面背景协调。
- 常见反例:页面深色但状态栏图标不可见。
- 推荐动作:联动窗口样式与安全区背景。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 23:导航栏
- 检查目标:底部栏使用独立 surface 语义。
- 常见反例:直接写死白色 TabBar。
- 推荐动作:检查选中与未选中图标对比。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 24:启动窗口
- 检查目标:启动背景与首屏背景连续。
- 常见反例:启动白屏后瞬间切深色。
- 推荐动作:让 start_window_background 对应首屏。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 25:聊天头部
- 检查目标:业务主题只覆盖约定区域。
- 常见反例:主题对象控制整个应用基础颜色。
- 推荐动作:限制主题影响范围,避免耦合。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 26:聊天气泡
- 检查目标:自己与对方气泡均有前景色。
- 常见反例:只换气泡背景不换文字。
- 推荐动作:成对验证背景与文字资源。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 27:聊天选择器
- 检查目标:主题预览在深色模式可识别。
- 常见反例:预览卡固定 #F5F5F5。
- 推荐动作:预览容器使用系统表面资源。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 28:热力图
- 检查目标:数据色阶与无数据色分离。
- 常见反例:浅色低值格在深色背景消失。
- 推荐动作:为图表建立独立数据调色板。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 29:趋势图
- 检查目标:折线与网格线分别资源化。
- 常见反例:网格线固定 #EEEEEE。
- 推荐动作:控制辅助线弱于数据线。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 30:情绪色
- 检查目标:业务情绪色不冒充系统状态色。
- 常见反例:开心绿色同时表示请求成功。
- 推荐动作:区分业务数据颜色与交互反馈。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 31:资源类型
- 检查目标:属性保持 Resource 或 ResourceColor。
- 常见反例:到处使用 as string。
- 推荐动作:让编译器检查资源用法。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 32:方法参数
- 检查目标:Builder 参数接受正确颜色类型。
- 常见反例:资源传入后被限制为 string。
- 推荐动作:从公共组件边界完成类型迁移。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 33:数组模型
- 检查目标:主题数组字段类型统一。
- 常见反例:部分字段支持 Resource、部分强转。
- 推荐动作:定义明确主题接口并逐字段核验。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 34:回退策略
- 检查目标:缺失资源时构建阶段即可发现。
- 常见反例:运行时静默回退到硬编码。
- 推荐动作:依赖资源校验而非隐藏问题。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 35:多模块资源
- 检查目标:明确 app 与 module 资源作用域。
- 常见反例:跨模块复制同名不同义资源。
- 推荐动作:公共语义放在可复用模块。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 36:命名冲突
- 检查目标:同类型资源名全局唯一且语义一致。
- 常见反例:同名资源在不同位置表达不同职责。
- 推荐动作:建立资源命名词典。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 37:资源审计
- 检查目标:定期搜索十六进制与 rgba。
- 常见反例:只靠人工浏览页面。
- 推荐动作:使用检索结果建立迁移清单。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 38:例外登记
- 检查目标:确需动态计算的颜色有明确理由。
- 常见反例:任何硬编码都以动画为借口保留。
- 推荐动作:记录例外、负责人和复查时间。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 39:浅色测试
- 检查目标:常用页面在浅色完整走查。
- 常见反例:只看设计稿截图。
- 推荐动作:覆盖登录、聊天、心情和个人页。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 40:深色测试
- 检查目标:系统深色下完整走查。
- 常见反例:只切换模拟器不操作弹层。
- 推荐动作:覆盖滚动、输入、弹窗和错误态。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 41:跟随系统
- 检查目标:运行中切换模式可正确刷新。
- 常见反例:必须重启后才显示新资源。
- 推荐动作:检查资源引用是否被转成固定字符串。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 42:冷启动
- 检查目标:深色冷启动无白色闪烁。
- 常见反例:启动页和首屏资源不一致。
- 推荐动作:同时核验启动背景与页面背景。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 43:前后台
- 检查目标:后台切换模式后返回可刷新。
- 常见反例:缓存旧主题对象。
- 推荐动作:检查生命周期中的主题读取时机。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 44:字体放大
- 检查目标:大字号下颜色层级仍清晰。
- 常见反例:依赖小字号和低对比维持布局。
- 推荐动作:联合可访问性测试。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 45:高亮模式
- 检查目标:系统强调或高对比场景可用。
- 常见反例:只追求低对比玻璃效果。
- 推荐动作:为核心操作保留清晰边界。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 46:截图对比
- 检查目标:建立明暗模式基准截图。
- 常见反例:改完只凭印象判断。
- 推荐动作:按页面保存前后对照证据。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 47:真实设备
- 检查目标:OLED 与 LCD 均检查。
- 常见反例:只在单一模拟器验证。
- 推荐动作:观察纯黑、暗灰与低亮度表现。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 48:性能检查
- 检查目标:资源读取不在高频循环中重复包装。
- 常见反例:列表每项执行复杂颜色转换。
- 推荐动作:直接传递资源或预先准备模型。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 49:列表稳定
- 检查目标:ForEach key 不因主题切换变化。
- 常见反例:颜色进入 key 导致整表重建。
- 推荐动作:key 只使用业务唯一标识。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 50:状态响应
- 检查目标:主题变化后 @State 引用链完整。
- 常见反例:把计算色作为固定 Builder 参数缓存。
- 推荐动作:让 UI 直接消费响应式状态或资源。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 51:发布检查
- 检查目标:release 包核验资源未被错误裁剪。
- 常见反例:只验证 debug。
- 推荐动作:检查资源引用与混淆配置。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 52:回归范围
- 检查目标:迁移不改变点击、路由和数据逻辑。
- 常见反例:顺手重构业务代码。
- 推荐动作:一次提交只处理可验证的颜色范围。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 53:设计协作
- 检查目标:语义色表与设计规范一致。
- 常见反例:开发自行新增近似色。
- 推荐动作:新颜色先归类再进入资源。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 54:国际化
- 检查目标:颜色不依赖中文文案长度。
- 常见反例:深色下长英文被背景裁切。
- 推荐动作:联合中英文与大字号检查。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 55:可访问性
- 检查目标:关键信息不只靠红绿区分。
- 常见反例:成功失败仅改变颜色。
- 推荐动作:增加图标、文本和状态描述。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 56:文档同步
- 检查目标:资源名含义可从代码直接理解。
- 常见反例:依赖口头约定。
- 推荐动作:通过稳定命名减少额外文档成本。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 57:代码评审
- 检查目标:新增硬编码颜色会被指出。
- 常见反例:资源化只做一次专项。
- 推荐动作:把语义色检查纳入日常评审。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 58:迁移节奏
- 检查目标:按页面小步替换并构建。
- 常见反例:一次替换全项目所有色值。
- 推荐动作:每批保持可回滚与可定位。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
检查项 59:验收结论
- 检查目标:每个页面都有明暗模式证据。
- 常见反例:只统计替换数量。
- 推荐动作:以用户可读、可操作作为最终标准。
- 验证环境:浅色模式、深色模式、运行中切换与冷启动。
- 通过标准:界面语义一致、文字可读、状态可辨且没有新增硬编码。
十二、推荐的落地分支策略
第一批只新增资源,不修改页面。
第二批迁移登录页和主导航,因为它们结构稳定、覆盖面清晰。
第三批迁移心情页的卡片、文字与分割线。
第四批处理聊天详情,并明确系统主题与用户主题的覆盖优先级。
第五批处理图表、透明玻璃层、阴影和渐变等复杂视觉。
每一批都应完成构建、明暗截图对比和主流程回归。
十三、常见反模式速查
| 反模式 | 直接后果 | 正确方向 |
|---|---|---|
| 所有白色替换成一个资源 | 页面层级消失 | 区分背景与表面 |
| dark 使用不同资源名 | 页面必须手动判断模式 | 同名资源限定覆盖 |
| 资源强转 string | 丢失资源能力与类型检查 | 保持 ResourceColor |
| 主题对象控制全应用 | 业务换肤与系统模式耦合 | 明确覆盖边界 |
| 只迁移实体色 | 玻璃层和阴影仍然刺眼 | 同步治理透明色 |
| 一次性全局替换 | 回归范围不可控 | 按页面渐进迁移 |
| 只看浅色设计稿 | 深色模式不可用 | 双模式真实设备验收 |
十四、总结
资源化颜色主题的核心不是把#009688搬进 JSON。
真正的工程收益来自三点:
- 用语义资源统一页面职责;
- 用限定目录自动承接系统深色模式;
- 用清晰边界保留聊天等业务换肤能力。
当颜色从“页面里的常量”升级为“系统可解析的设计语义”,深色模式、视觉一致性和后续维护才真正进入可治理状态。