本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
鸿蒙(HarmonyOS)应用开发中,资源分类与访问是适配多设备、多场景的核心机制。以下是详细的分类说明和访问示例:
一、资源分类
鸿蒙资源文件按存储位置和用途分为以下类型:
1. 基础资源目录
base
目录 默认存在的目录,存放通用资源。子目录包括:element
:字符串、颜色、布尔值等基础元素(如string.json
、color.json
)。media
:图片、音频等媒体文件(如icon.png
)。profile
:动画、布局等配置文件(如test_profile.json
) 。
2. 限定词目录
- 命名规则: 由语言、屏幕方向、设备类型等限定词组合命名,例如:
zh_CN
(简体中文)en_GB-vertical-car-mdpi
(英式英语+竖屏+车机+中密度屏幕) 。
- 匹配优先级: 系统会根据设备特征自动匹配最接近的限定词目录,未找到则回退到
base
目录。
3. 原始文件目录
rawfile
: 文件保持原始格式,不编译不压缩,通过路径直接访问(如$rawfile('test.png')
) 。
resfile
: 类似rawfile
,但安装后解压到应用沙箱,通过Context.resourceDir
获取路径访问。
二、资源访问方式
1. 编译型资源访问
通过$r('app.type.name')
格式引用,其中:
app
:表示base
或限定词目录。type
:资源类型(string
、color
、media
等)。name
:资源名称(对应JSON中的name
字段)。
示例代码:
// 引用字符串和颜色资源
Text($r('app.string.hello')) // 从string.json中读取
.fontColor($r('app.color.primary')) // 从color.json中读取
.fontSize($r('app.float.font_size')) // 从float.json中读取
// 引用图片资源
Image($r('app.media.icon')) // 从media目录加载图片
// 带参数的多语言字符串
Text($r('app.string.welcome', "用户")) // 替换string.json中的%s
JSON文件示例(resources/base/element/string.json
):
{
"string": [
{ "name": "hello", "value": "你好" },
{ "name": "welcome", "value": "欢迎%s" }
]
}
2. 原始文件访问
通过$rawfile
或文件API直接访问路径:
// 引用rawfile目录下的图片
Image($rawfile('images/background.png'))
// 访问resfile目录(需沙箱路径)
let context = getContext() as common.UIAbilityContext;
let resFilePath = context.resourceDir + '/resfile/config.json';
3. 系统资源访问
直接使用预置资源ID(需查阅系统资源表):
Text($r('sys.string.APP_NAME')) // 系统应用名称
.fontColor($r('sys.color.ohos_id_color_foreground')) // 系统前景色
三、多设备适配示例
场景:为手机和车机适配不同图标
- 目录结构:
resources
|---base
| |---media
| |---icon.png // 默认图标
|---en_GB-car-mdpi
| |---media
| |---icon.png // 车机专用图标
代码调用:
Image($r('app.media.icon')) // 自动匹配设备类型
当设备为车机时,优先加载en_GB-car-mdpi/media/icon.png。
四、屏幕密度与切图适配规则
为不同屏幕密度(如2x、3x)提供适配的切图是保证多设备显示效果的关键
1. 屏幕密度分类
设备类型 | 屏幕密度(dpi) | 切图目录后缀 | 典型设备 |
---|---|---|---|
低密度屏幕(ldpi) | 0-120dpi | mdpi | 部分车机屏幕 |
中密度屏幕(mdpi) | 120-160dpi | mdpi | 标准手机(旧机型) |
高密度屏幕(hdpi) | 160-240dpi | hdpi | 主流手机(如华为P40) |
超高密度(xhdpi) | 240-320dpi | xhdpi | 高端手机(2x屏) |
超超高密度(xxhdpi) | 320-480dpi | xxhdpi | 旗舰手机(3x屏,如Mate 50) |
2. 切图目录命名规则
在 resources
目录下按密度创建子目录:
resources
├── base
│ └── media
│ └── icon.png # 默认切图(1x基准图)
├── hdpi
│ └── media
│ └── icon.png # 1.5x切图(hdpi)
├── xhdpi
│ └── media
│ └── icon.png # 2x切图(xhdpi)
└── xxhdpi
└── media
└── icon.png # 3x切图(xxhdpi)
3、实际开发示例
场景:为不同密度屏幕提供适配图标
-
准备切图文件
- 基准图:
base/media/icon.png
(100×100px,1x) - 2x切图:
xhdpi/media/icon.png
(200×200px) - 3x切图:
xxhdpi/media/icon.png
(300×300px)
- 基准图:
-
代码中引用资源
Image($r('app.media.icon')) // 自动匹配设备密度
.width(100) // 逻辑像素单位(实际显示大小由系统自动缩放)
.height(100)
3.系统自动匹配流程
4、验证适配效果
1. 手动指定密度测试
在 module.json5
中强制指定屏幕密度进行测试:
{
"deviceTypes": ["phone", "tablet"],
"abilities": [
{
"name": "EntryAbility",
"screenDensity": "xxhdpi" // 强制使用3x资源
}
]
}
2. 动态获取当前密度
通过 display
模块获取实际屏幕信息:
import display from '@ohos.display';
let displayInfo = display.getDefaultDisplaySync();
console.log(`当前屏幕密度: ${displayInfo.densityDPI}dpi`);
// 输出示例: 当前屏幕密度: 480dpi(3x设备)
五、高级适配技巧
1. SVG矢量图适配(推荐)
- 优势:单文件适配所有密度,无需多套切图
- 实现方法:
Image($r('app.media.vector_icon')) // 引用resources/base/media/vector_icon.svg .width(100) .height(100)
2. 代码控制缩放比例
根据密度动态调整显示大小:
// 计算实际显示尺寸(以1x为基准)
function getScaledSize(baseSize: number): number {
let density = display.getDefaultDisplaySync().densityDPI / 160; // 160为mdpi基准
return baseSize * density;
}
Image($r('app.media.icon'))
.width(getScaledSize(100)) // 在3x设备上实际渲染为300px
.height(getScaledSize(100))
3. 多语言+多密度组合适配
目录结构示例(英文+3x屏):
resources
└── en_GB-xxhdpi
└── media
└── icon.png # 英文环境的3x切图
六、注意事项
- 文件层级限制:
element
、media
等资源组目录下不能创建子目录,否则编译报错 。 - 资源ID生成规则: 非
rawfile
资源会被编译为二进制,ID由type
和name
组合生成 。 - 多工程资源管理: Stage模型下,公共资源需放在
AppScope/resources
目录 - 切图命名一致性:所有密度目录中的同名切图必须保持相同语义(如都是“首页图标”)。
- 兜底策略:确保
base
目录存在默认切图,避免匹配失败时无图显示。 - 内存优化:3x切图体积较大,避免在列表项等高频场景滥用。