鸿蒙如何适配2x、3x不同密度的切图_鸿蒙2x 3x切图资源管理
本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
鸿蒙(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. 屏幕密度分类
mdpi
mdpi
hdpi
xhdpi
xxhdpi
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切图体积较大,避免在列表项等高频场景滥用。