【HarmonyOS实战】 暗色模式与国际化:一套代码适配多套皮肤和语言
文章目录
- 前言
- 一、资源文件的优先级规则
- 二、项目的资源目录结构
- 三、颜色资源详解
- 3.1 base/element/color.json(亮色默认)
- 3.2 dark/element/color.json(暗色覆盖)
- 3.3 代码中使用
- 四、多语言字符串详解
- 4.1 base/element/string.json(英文默认)
- 4.2 zh_CN/element/string.json(中文覆盖)
- 4.3 代码中使用
- 五、应用标签的多语言
- 六、为什么项目强制了亮色模式?
- 七、支持更多语言
- 带格式的字符串
- 八、颜色资源设计原则
- 总结
前言
一个好的应用应该:手机开了暗色模式,App 自动变暗;手机语言改成英文,App 自动说英文。
HarmonyOS 的资源系统天然支持这些能力,只要你按规范组织资源文件,这些适配自动完成,不需要写任何判断代码。
这篇文章结合项目,讲清楚暗色模式和多语言是怎么工作的,以及项目为什么主动关闭了暗色模式(以及关掉的代价是什么)。
项目预览
一、资源文件的优先级规则
HarmonyOS 加载资源时,按照以下优先级从高到低查找:
语言+地区限定 > 语言限定 > 主题限定 > 默认(base) 示例:设备语言=zh_CN,暗色模式 查找顺序: 1. zh_CN/dark/element/color.json (语言+暗色) 2. zh_CN/element/color.json (中文颜色) 3. dark/element/color.json (暗色模式颜色) 4. base/element/color.json (默认颜色)← 最终兜底字符串的查找顺序:
1. zh_CN/element/string.json (中文字符串) 2. base/element/string.json (英文默认字符串)整个过程完全自动,你只需要在对应目录下放好文件,框架自动匹配。
二、项目的资源目录结构
resources/ ├── base/ # 默认资源(兜底) │ └── element/ │ ├── color.json # 亮色模式颜色 │ └── string.json # 英文字符串 ├── dark/ # 暗色模式覆盖 │ └── element/ │ └── color.json # 暗色模式颜色(只定义需要覆盖的) └── zh_CN/ # 中文覆盖 └── element/ └── string.json # 中文字符串(覆盖英文默认)三、颜色资源详解
3.1 base/element/color.json(亮色默认)
{"color":[{"name":"start_window_background","value":"#FFFFFF"},{"name":"page_background","value":"#F1F3F5"},{"name":"gas_station_name_color","value":"#182431"},{"name":"gas_station_addr_color","value":"#99182431"},{"name":"bind_sheet_background","value":"#FFFFFF"}]}颜色格式:
#FFFFFF:不透明白色(标准 RGB)#99182431:带透明度(#AARRGGBB,99≈ 60% 不透明度,182431是深蓝色)
3.2 dark/element/color.json(暗色覆盖)
{"color":[{"name":"start_window_background","value":"#000000"}]}暗色文件只定义需要变化的颜色,没定义的自动用base/里的值。
这里只覆盖了start_window_background(黑色),这意味着其他颜色(page_background、文字颜色等)在暗色模式下和亮色一样——这是项目有意为之的(因为强制了亮色模式)。
3.3 代码中使用
// 使用颜色资源引用,自动适配亮色/暗色Column().backgroundColor($r('app.color.start_window_background'))Text('站名').fontColor($r('app.color.gas_station_name_color'))不需要任何判断,系统自动选择对应的颜色。
四、多语言字符串详解
4.1 base/element/string.json(英文默认)
{"string":[{"name":"EntryAbility_label","value":"nearby gas station"},{"name":"gas_station","value":"gas station"},{"name":"car_life","value":"car life"},{"name":"nearby","value":"vicinity"},{"name":"navigation_text","value":"Navigation"},{"name":"calculate_text2","value":"Km"},{"name":"Stay_tuned","value":"Stay tuned"}]}4.2 zh_CN/element/string.json(中文覆盖)
{"string":[{"name":"EntryAbility_label","value":"附近加油站"},{"name":"gas_station","value":"加油站"},{"name":"car_life","value":"汽车生活"},{"name":"nearby","value":"附近"},{"name":"navigation_text","value":"导航"},{"name":"calculate_text2","value":"公里"},{"name":"Stay_tuned","value":"敬请期待"}]}4.3 代码中使用
// 直接用资源引用,语言自动切换Text($r('app.string.car_life'))// 中文显示"汽车生活",英文显示"car life"// 获取字符串值(用于逻辑处理)letunitText=this.getUIContext().getHostContext()?.resourceManager.getStringSync($r('app.string.calculate_text2').id);// 中文设备:unitText = "公里"// 英文设备:unitText = "Km"五、应用标签的多语言
string.json里有一个特殊的 key:EntryAbility_label,这是应用显示在桌面上的名称。
在module.json5里引用它:
{"module":{"abilities":[{"name":"EntryAbility","label":"$string:EntryAbility_label"// 引用字符串资源}]}}中文系统显示"附近加油站",英文系统显示"nearby gas station",就是这么配置的。
六、为什么项目强制了亮色模式?
// EntryAbility.onCreate()this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT);这行代码让整个 App 强制使用亮色模式,即使系统开了暗色,App 也不跟着变暗。
原因分析:
- 地图类应用有精心设计的配色方案(以白色为主色调)
- 目前只设计了亮色主题,暗色主题颜色没有仔细调整
- 贸然跟随系统暗色可能导致 UI 不协调(比如文字看不清)
代价:
- 暗色模式下,这个 App 依然是亮色,用户体验可能不一致
dark/目录里定义的颜色不会生效(因为强制了亮色)
正确做法(如果要完整支持暗色):
- 删除
setColorMode这行代码 - 在
dark/element/color.json里为所有颜色定义暗色版本 - 测试每个页面在暗色模式下的显示效果
七、支持更多语言
如果想支持更多语言,只需要添加对应的语言目录:
resources/ ├── base/element/string.json # 英文(默认) ├── zh_CN/element/string.json # 中文简体 ├── zh_TW/element/string.json # 中文繁体 ├── ja/element/string.json # 日语 └── ko/element/string.json # 韩语每个目录里的string.json只需要定义那个语言的字符串翻译,格式和base/完全一样。
带格式的字符串
如果字符串里有动态内容(如用户名),可以用占位符:
{"name":"welcome_message","value":"欢迎,%s!"}代码里用资源管理器格式化:
letmsg=resourceManager.getStringByNameSync('welcome_message',['张三']);// 结果:"欢迎,张三!"八、颜色资源设计原则
设计暗色模式颜色时,主要考虑:
| 场景 | 亮色 | 暗色 |
|---|---|---|
| 主背景 | 白色 (#FFFFFF) | 深灰 (#1A1A1A) |
| 卡片背景 | 浅灰 (#F1F3F5) | 深色 (#2A2A2A) |
| 主要文字 | 深色 (#182431) | 浅色 (#E8E8E8) |
| 次要文字 | 透明深色 (#99182431) | 透明浅色 (#99E8E8E8) |
| 分割线 | 浅灰 (#E5E5E5) | 深灰 (#3A3A3A) |
总结
HarmonyOS 的资源适配系统非常强大:
- 暗色模式:在
dark/element/color.json里定义暗色颜色,代码无感知自动切换 - 多语言:在
zh_CN/element/string.json(及其他语言目录)定义翻译,代码无感知 - 资源引用:用
$r('app.color.xxx')和$r('app.string.xxx'),不要硬编码颜色和文字 - 优先级:语言特定 > 主题特定 > base 默认,自动兜底
项目强制亮色模式是一个设计决策,代价是暗色用户的体验一致性。如果要完整支持暗色,需要补全dark/目录里所有颜色的暗色版本,并删除setColorMode强制代码。
下一篇是最后一篇——项目总结与优化建议,把整个系列串起来,并给出实际项目中可以做的优化点。
