HarmonyOS 资源系统完全指南:$r() 引用、资源限定符与多分辨率适配
文章目录
- 前言
- 一、资源目录结构
- 1.1 resources 目录
- 1.2 本项目资源引用分析
- 二、屏幕单位:vp、fp、px 的区别
- 2.1 三种单位说明
- 2.2 为什么用 vp 而不是 px?
- 三、颜色资源与深色模式适配
- 3.1 定义颜色资源
- 3.2 系统颜色资源(sys.color)
- 四、字符串资源与多语言
- 4.1 定义字符串
- 4.2 代码中获取字符串值
- 五、图片资源与多密度适配
- 5.1 不同密度的图片目录
- 5.2 推荐:使用 SVG 矢量图
- 六、响应式布局:平板适配
- 总结
前言
一个优秀的 HarmonyOS 应用需要在不同屏幕尺寸(手机/平板)、不同屏幕密度(标准/高清/超高清)、不同主题(浅色/深色)下都能保持良好体验。这些都依赖资源管理系统的正确使用。本篇结合项目中$r('app.color.xxx')、$r('app.string.xxx')、$r('app.media.xxx')的使用,系统讲解 HarmonyOS 资源体系。
一、资源目录结构
1.1 resources 目录
entry/src/main/resources/ ├── base/ ← 默认资源(所有设备) │ ├── element/ │ │ ├── color.json ← 颜色定义 │ │ ├── string.json ← 字符串 │ │ └── integer.json ← 整数常量 │ ├── media/ ← 图片/图标 │ │ ├── station.svg │ │ └── icon.png │ └── profile/ ← 配置文件(路由映射等) │ └── route_map.json ├── dark/ ← 深色模式资源(覆盖 base) │ └── element/ │ └── color.json ← 深色模式颜色 ├── zh_CN/ ← 中文资源(多语言) │ └── element/ │ └── string.json ├── en_US/ ← 英文资源 │ └── element/ │ └── string.json └── rawfile/ ← 原始文件(不参与资源编译)1.2 本项目资源引用分析
// 颜色资源(自动适配深色模式).backgroundColor($r('app.color.page_background')).backgroundColor($r('app.color.start_window_background')).fontColor($r('app.color.gas_station_name_color')).color($r('sys.color.mask_fourth'))// ← sys.color 是系统提供的颜色// 字符串资源(自动多语言)Text($r('app.string.gas_station'))Text($r('app.string.car_life'))// 图片/图标资源Image($r('app.media.image1'))Image($r('app.media.chevron_right'))Image($r('app.media.back'))二、屏幕单位:vp、fp、px 的区别
2.1 三种单位说明
| 单位 | 全称 | 说明 | 推荐场景 |
|---|---|---|---|
vp | Virtual Pixel(虚拟像素) | 与屏幕密度无关的逻辑像素,ArkUI 默认单位 | 布局尺寸、间距 |
fp | Font Pixel | 随系统字体大小设置缩放 | 字体大小 |
px | Physical Pixel(物理像素) | 实际屏幕像素,不同设备值不同 | 尽量避免使用 |
% | 百分比 | 相对于父容器的百分比 | 弹性布局 |
// 推荐写法(本项目的做法)Text('加油站').fontSize(16)// 默认 fp 单位,字体大小Column().width(200)// 默认 vp 单位,布局宽度Row().height('100%')// 百分比// 等价显式写法Text('加油站').fontSize(16)// 等同于 '16fp'Column().width('200vp')2.2 为什么用 vp 而不是 px?
低密度屏幕(160dpi):1vp = 1px 标准密度屏幕(320dpi):1vp = 2px 高密度屏幕(480dpi):1vp = 3px 你写 200vp: ─ 低密度屏幕显示 200px(看起来一样大) ─ 高密度屏幕显示 600px(看起来还是一样大!) 你写 200px: ─ 低密度屏幕显示 200px(正常) ─ 高密度屏幕显示 200px(看起来只有正常大小的1/3,超级小!)三、颜色资源与深色模式适配
3.1 定义颜色资源
resources/base/element/color.json:
{"color":[{"name":"page_background","value":"#F5F7FA"},{"name":"start_window_background","value":"#FFFFFF"},{"name":"gas_station_name_color","value":"#333333"},{"name":"gas_station_addr_color","value":"#999999"},{"name":"bind_sheet_background","value":"#F5F7FA"}]}resources/dark/element/color.json(深色模式覆盖):
{"color":[{"name":"page_background","value":"#1A1A1A"},{"name":"start_window_background","value":"#2C2C2C"},{"name":"gas_station_name_color","value":"#E0E0E0"},{"name":"gas_station_addr_color","value":"#888888"},{"name":"bind_sheet_background","value":"#252525"}]}在代码中引用:
// 自动适配:浅色模式用 base/color.json,深色模式用 dark/color.json.backgroundColor($r('app.color.page_background')).fontColor($r('app.color.gas_station_name_color'))3.2 系统颜色资源(sys.color)
系统提供的语义化颜色,在所有 HarmonyOS 应用中保持一致:
// 本项目使用的系统颜色.color($r('sys.color.mask_fourth'))// 遮罩颜色(自动适配深色模式)// 其他常用系统颜色$r('sys.color.brand')// 品牌主色$r('sys.color.warning')// 警告色$r('sys.color.error')// 错误色$r('sys.color.font_primary')// 主文字色$r('sys.color.font_secondary')// 次要文字色$r('sys.color.background_primary')// 主背景色四、字符串资源与多语言
4.1 定义字符串
resources/base/element/string.json:
{"string":[{"name":"gas_station","value":"加油站"},{"name":"car_life","value":"车生活"},{"name":"Stay_tuned","value":"敬请期待"},{"name":"calculate_text2","value":"km"},{"name":"reason_location","value":"查找附近加油站需要您的位置信息"}]}resources/en_US/element/string.json(英文):
{"string":[{"name":"gas_station","value":"Gas Station"},{"name":"car_life","value":"Car Life"},{"name":"Stay_tuned","value":"Stay Tuned"}]}在代码中引用:
// 自动根据系统语言选择对应翻译Text($r('app.string.gas_station'))// 中文系统显示"加油站",英文系统显示"Gas Station".title($r('app.string.car_life'))// 中文显示"车生活",英文显示"Car Life"4.2 代码中获取字符串值
// 在非 UI 代码中获取字符串(如 Logger 输出)conststationText=this.getUIContext().getHostContext()?.resourceManager.getStringSync($r('app.string.gas_station').id);// stationText = '加油站'(或当前语言对应值)五、图片资源与多密度适配
5.1 不同密度的图片目录
resources/ ├── base/media/ │ └── icon.png ← 1x(基准密度) ├── mdpi/media/ ← 1x(Medium DPI,160dpi) │ └── icon.png ├── hdpi/media/ ← 1.5x(High DPI,240dpi) │ └── icon.png ├── xhdpi/media/ ← 2x(Extra High DPI,320dpi) │ └── icon.png └── xxhdpi/media/ ← 3x(480dpi) └── icon.png系统自动根据设备屏幕密度选择对应目录的图片。
5.2 推荐:使用 SVG 矢量图
// SVG 矢量图在任何密度下都清晰,不需要多套图Image($r('app.media.chevron_right'))// 如果是 svg,一套搞定所有密度.width(16).height(16)// PNG 位图:需要提供多套(或使用较大尺寸)Image($r('app.media.station'))// station.svg(本项目用了 SVG)本项目的station.svg用作地图 Marker 图标,SVG 格式在任何缩放比例下都保持清晰——这是一个正确的设计选择。
六、响应式布局:平板适配
@Entry@Componentstruct ResponsiveLayout{@StorageProp('deviceType')deviceType:string='phone';build(){if(this.deviceType==='tablet'){// 平板:两栏布局Row(){// 左栏:加油站列表Column(){Text('加油站列表').fontSize(16).padding(16)}.width('40%').height('100%').backgroundColor('#FFFFFF')Divider().vertical(true).height('100%')// 右栏:地图Column(){Text('地图区域').fontSize(16).padding(16)}.layoutWeight(1).height('100%').backgroundColor('#F5F7FA')}}else{// 手机:单栏布局Column(){Text('手机版布局(单栏)').fontSize(16).padding(16)}.width('100%').height('100%')}}}总结
HarmonyOS 资源系统通过资源限定符目录实现对不同设备、不同密度、不同语言的自动适配:深色模式用dark/目录,英文用en_US/目录,高密度用xhdpi/目录。始终使用vp而非px作为布局单位,使用$r()引用资源而非硬编码字符串,使用 SVG 矢量图代替多套 PNG,这三点是 HarmonyOS 多端适配的核心原则。
