当前位置: 首页 > news >正文

【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:带透明度(#AARRGGBB99≈ 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 也不跟着变暗。

原因分析

  1. 地图类应用有精心设计的配色方案(以白色为主色调)
  2. 目前只设计了亮色主题,暗色主题颜色没有仔细调整
  3. 贸然跟随系统暗色可能导致 UI 不协调(比如文字看不清)

代价

  • 暗色模式下,这个 App 依然是亮色,用户体验可能不一致
  • dark/目录里定义的颜色不会生效(因为强制了亮色)

正确做法(如果要完整支持暗色)

  1. 删除setColorMode这行代码
  2. dark/element/color.json里为所有颜色定义暗色版本
  3. 测试每个页面在暗色模式下的显示效果

七、支持更多语言

如果想支持更多语言,只需要添加对应的语言目录:

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 的资源适配系统非常强大:

  1. 暗色模式:在dark/element/color.json里定义暗色颜色,代码无感知自动切换
  2. 多语言:在zh_CN/element/string.json(及其他语言目录)定义翻译,代码无感知
  3. 资源引用:用$r('app.color.xxx')$r('app.string.xxx'),不要硬编码颜色和文字
  4. 优先级:语言特定 > 主题特定 > base 默认,自动兜底

项目强制亮色模式是一个设计决策,代价是暗色用户的体验一致性。如果要完整支持暗色,需要补全dark/目录里所有颜色的暗色版本,并删除setColorMode强制代码。

下一篇是最后一篇——项目总结与优化建议,把整个系列串起来,并给出实际项目中可以做的优化点。

http://www.jsqmd.com/news/965733/

相关文章:

  • AI虚拟城市主义:生成式模型与城市身份量化分析
  • 告别复制粘贴:手把手教你为任意STM32F4开发板定制MicroPython引脚配置文件
  • 别再手动试错了!用Minitab 21做全因子DOE,5步搞定工艺参数优化
  • 从Linux命令行到MinIO存储桶:一份给运维的mc命令对照手册(含实战脚本)
  • e2 studio调试总失败?别慌,先检查这3个配置项(含Connection Settings详解)
  • 物理信息神经网络与随机增广拉格朗日方法解析
  • 别再死记硬背了!用Proteus 8.9仿真51单片机,手把手教你搭建第一个流水灯电路
  • CANoe自动化配置进阶:如何用CommunicationSetup接口批量管理你的应用模型和数据源
  • 用Arduino Uno和PAJ7620手势传感器做个智能台灯:手势控制开关/调光/流水灯(附完整代码)
  • 2026年5月国内电动两轮高端改装灯具品牌排行:行业电动两轮高端灯具/顶级灯具设计研发/高端两轮灯具/高端灯具研发首家/选择指南 - 优质品牌商家
  • 从零开始搞懂SoC:芯片设计中的‘大脑’与‘高速公路’(AMBA总线篇)
  • 手把手教你将GCNv2特征提取器‘抠’出来做双目匹配测试(附完整C++代码)
  • 3分钟掌握Keyviz:让屏幕操作从此不再神秘
  • 从《半日》到代码人生:一个程序员如何用技术工具高效啃下大学英语精读(附Anki+欧路词典配置)
  • 从金融量化到数据分析:Pandas 0.20.0的诞生故事与核心设计思想
  • K8s介绍(1)
  • 从赌徒破产到网页排名:齐次马尔可夫链在算法面试中的高频考点解析
  • 用Arduino Uno和PAJ7620U2手势传感器做个智能灯控:从接线到代码调试的完整避坑指南
  • 从Tab切换案例出发,手把手教你用Chrome DevTools调试JavaScript事件与DOM状态
  • 概率密度函数与区域核:概念、验证与应用
  • GprMax正演模拟避坑指南:除了介电常数,这3个参数设置不当也会导致图像‘消失’
  • 实战指南:基于快马生成的php应用骨架,快速构建企业级内容管理系统
  • 从TC2到TC3,你的PLC代码升级了吗?聊聊那些必须注意的数据类型与对齐问题
  • SAP ABAP ALV编辑实战:手把手教你实现单元格联动更新与数据校验(附完整代码)
  • 从屏幕到代码:ColorWanted免费取色器的终极指南
  • 从STM32转战NXP LPC54114?手把手教你用Keil5点亮第一个LED(附完整工程)
  • 别再只用线性回归了!用sklearn的Ridge和Lasso轻松搞定特征多、样本少的预测难题
  • 别再直接用经纬度了!用Python的mgtwr包做GTWR建模,手把手教你处理时空数据的正确姿势
  • 不止是发现邻居:拆解IEEE 1905.1拓扑协议如何成为智能家居‘无缝漫游’的幕后功臣
  • 从Eclipse老手到STS新手:这10个SpringBoot开发必备设置,你配好了吗?