HarmonyOS应用开发实战:猫猫大作战-`$r` 与 `$rawfile` 的区别、资源目录结构、多分辨率适配
2026/7/28 19:40:11 网站建设 项目流程

前言

前面我们大量用 Emoji(🐱、🔥、🏆)做图标——简单但不专业。真正的游戏需要 PNG/JPG/SVG 图集:猫咪精灵图、UI 图标、背景插画。HarmonyOS 加载图片资源有两条路径——$r()引用编译期资源和**$rawfile()引用原始文件**。两者用法、性能、适用场景完全不同。

本篇以「猫猫大作战」图标资源加载为锚点,把$r$rawfile的区别、资源目录结构、多分辨率适配三大要点讲透。

提示:本系列不讲 ArkTS 基础语法与环境搭建,假设你已跟完第 1–26 篇。本篇是布局进阶的第七篇。

一、场景拆解:图标资源加载

回顾「猫猫大作战」主菜单标题图标(第 1 篇):

// 来源:entry/src/main/ets/pages/Index.ets MainMenuView() Text('🐱').fontSize(72)

这是用 Emoji 文字做图标。现在想换成专业的 PNG 图标cat_logo.png——需要 Image 组件 + 资源引用:

// 写法 1:$r() 引用编译期资源(推荐) Image($r('app.media.cat_logo')) .width(72).height(72) // 写法 2:$rawfile() 引用原始文件 Image($rawfile('icons/cat_logo.png')) .width(72).height(72)

关键区别

维度$r('app.media.xxx')$rawfile('path/xxx')
资源位置resources/base/media/resources/rawfile/
编译处理编译期索引、可多语言多分辨率原样打包,不处理
引用方式资源名(无扩展名)相对路径(含扩展名)
适用UI 图标、标准图片动效 JSON、字体、大文件

二、$r 编译期资源引用

2.1 资源目录结构

entry/src/main/resources/ ├─ base/ # 默认资源(所有设备匹配) │ ├─ element/ # string.json, color.json, float.json │ ├─ media/ # 图片、音频、视频 │ │ ├─ cat_logo.png │ │ ├─ icon_pause.png │ │ └─ bg_main.jpg │ └─ profile/ # 自定义 JSON 配置 ├─ zh_CN/element/ # 中文语言覆盖 ├─ en_US/element/ # 英文语言覆盖 ├─ dark/element/ # 暗色模式覆盖 └─ rawfile/ # 原始文件(不编译) └─ icons/cat_logo.png

2.2 $r 三种资源类型

// 1. media:图片/音频/视频 Image($r('app.media.cat_logo')) // 2. string:字符串 Text($r('app.string.hello_world')) // 3. color/float:颜色/尺寸 Text('A').fontColor($r('app.color.primary')) Text('B').fontSize($r('app.float.title_size'))

关键经验$r('app.<type>.<name>')引用资源——typemedia/string/color/float/plural等,name是资源名(不含扩展名)。

2.3 命名规则

// ✅ 合法资源名 $r('app.media.cat_logo') // 蛇形命名 $r('app.media.icon_pause') $r('app.string.hello_world') // ❌ 非法资源名 $r('app.media.catLogo') // 驼峰,ArkTS 不允许 $r('app.media.cat-logo') // 含连字符 $r('app.media.cat logo') // 含空格

提示:HarmonyOS 资源名必须蛇形命名(snake_case)——驼峰会编译报错。

2.4 多分辨率适配

HarmonyOS 自动按设备密度加载对应 dpi 的图片:

resources/ ├─ base/media/cat_logo.png # 默认(mdpi 1x) ├─ fiberscale-2x/media/cat_logo.png # 2x 高分辨率 └─ fiberscale-3x/media/cat_logo.png # 3x 超高分辨率
设备密度加载的图片
mdpi(1x)base/media/cat_logo.png
xhdpi(2x)fiberscale-2x/media/cat_logo.png
xxhdpi(3x)fiberscale-3x/media/cat_logo.png

实战经验UI 图标准备 1x、2x、3x 三套——分别放在base/mediafiberscale-2x/mediafiberscale-3x/media,系统自动选最清晰的。

三、$rawfile 原始文件引用

3.1 适用场景

// 1. Lottie 动效 JSON Image($rawfile('lottie/loading.json')) // 2. 自定义字体 TTF Font().registerFont({ familyName: 'Custom', familySrc: $rawfile('fonts/Custom.ttf') }) // 3. 大型背景图(不想编译处理) Image($rawfile('bg/level_1.jpg')) // 4. 配置 JSON 文件 const config = fs.readSync($rawfile('config/game.json'))

3.2 路径规则

$rawfile('icons/cat_logo.png') // 相对 resources/rawfile/ 的路径 // 完整路径:resources/rawfile/icons/cat_logo.png

关键经验$rawfile路径必须包含扩展名——与$r省略扩展名不同。

3.3 $rawfile vs $r 的核心差异

维度$r$rawfile
编译期索引✅ 拼写错误编译报错❌ 运行时才报错
多语言覆盖zh_CN//en_US/自动切❌ 不支持
多分辨率fiberscale-2x/自动选❌ 不支持
暗色模式dark/自动切❌ 不支持
文件类型限制限图片/音频/视频任意文件
适用UI 图标、标准化资源Lottie、字体、大文件

实战经验能用 $r 就用 $r——编译期校验、多端适配都免费。只有 Lottie 动效、自定义字体这种「非标准资源」才用 $rawfile。

四、用 $r 改造主菜单图标

4.1 替换标题 Emoji 为 PNG 图标

假设已放置resources/base/media/cat_logo.png

@Builder MainMenuView() { Column() { Spacer().height('15%') // 改造:Emoji → $r PNG 图标 Image($r('app.media.cat_logo')) .width(72) .height(72) .margin({ bottom: 8 }) Text('猫猫大作战').fontSize(36).fontWeight(FontWeight.Bold).fontColor('#2C3E50').margin({ bottom: 8 }) Text('合并进化 · 策略消除').fontSize(16).fontColor('#95A5A6').margin({ bottom: 48 }) if (this.highScore > 0) { Row() { // 改造:🏆 Emoji → $r PNG 奖杯图标 Image($r('app.media.icon_trophy')) .width(20).height(20) Text(` 最高分: ${this.highScore}`).fontSize(16).fontColor('#F1C40F').fontWeight(FontWeight.Bold) }.margin({ bottom: 32 }) } // 开始游戏按钮 Button('开始游戏') .width('70%').height(56) .fontSize(20).fontWeight(FontWeight.Bold) .fontColor('#FFFFFF').backgroundColor('#2ECC71') .borderRadius(28) .shadow({ radius: 8, color: 'rgba(46, 204, 113, 0.4)', offsetY: 4 }) .onClick(() => { this.startGame(); }) Spacer().height(24) // 规则面板(第 25 篇) Scroll() { /* ... */ }.height(180) Spacer() } .width('100%').height('100%') .linearGradient({ direction: GradientDirection.Bottom, colors: [['#E8F4F8', 0.0], ['#D6EEF5', 0.5], ['#C9E8F2', 1.0]] }) .alignItems(HorizontalAlign.Center) }

4.2 Image 组件常用属性

Image($r('app.media.cat_logo')) .width(72).height(72) // 尺寸 .objectFit(ImageFit.Contain) // 缩放模式 .borderRadius(12) // 圆角 .interpolation(ImageInterpolation.High) // 高质量插值 .draggable(false) // 禁止拖拽 .alt($r('app.media.placeholder')) // 加载失败占位图

4.3 objectFit 缩放模式

ImageFit 值效果适用
Contain等比缩放,完整显示,可能留白UI 图标(推荐)
Cover等比缩放,填满容器,可能裁剪背景图
Fill拉伸填满,变形不推荐
None原始尺寸,可能溢出精确像素
ScaleDown等比缩小,不放大缩略图

实战经验UI 图标用 Contain——保证图标完整不变形;全屏背景用 Cover——填满屏幕不裁剪主体。

五、资源访问的编程式 API

5.1 resourceManager 获取资源

import { common } from '@kit.AbilityKit'; const context = getContext(this) as common.UIAbilityContext; const resMgr = context.resourceManager; // 同步获取字符串 const str: string = resMgr.getStringSync($r('app.string.hello_world').id); // 同步获取颜色 const color: number = resMgr.getColorSync($r('app.color.primary').id); // 异步获取 rawfile 文件描述符 const rawFd = await resMgr.getRawFd('config/game.json'); // rawFd = { fd, offset, length }

5.2 getStringByNameSync 按名取值

// 按资源名(不含 app. 前缀)取字符串 const greeting: string = resMgr.getStringByNameSync('hello_world');

实战经验UI 层用$r()直接渲染,逻辑层用resourceManager取值——例如要把字符串塞进 ArrayBuffer 时。

六、踩坑提示

6.1 资源名拼错

// ❌ 错误:拼写错误,编译报错 Image($r('app.media.cat_Logo')) // L 大写 Image($r('app.media.catlogo')) // 缺下划线 // ✅ 正确:与文件名完全一致(蛇形) Image($r('app.media.cat_logo'))

6.2 $r 引用 rawfile 资源

// ❌ 错误:$r 不能引用 rawfile 下的文件 Image($r('app.media.cat_logo')) // 但 cat_logo.png 在 rawfile/icons/ 下 // ✅ 正确:rawfile 用 $rawfile Image($rawfile('icons/cat_logo.png'))

6.3 多分辨率图片缺失

# ❌ 只有 3x 图,1x 设备加载 3x 图缩放,模糊 resources/base/media/ # 空 resources/fiberscale-3x/media/cat_logo.png # ✅ 至少提供 1x 和 3x resources/base/media/cat_logo.png # 1x resources/fiberscale-3x/media/cat_logo.png # 3x

6.4 Image 不设宽高

// ❌ 错误:不设尺寸,Image 按图片原始像素渲染,可能撑爆屏幕 Image($r('app.media.cat_logo')) // ✅ 正确:显式设尺寸 Image($r('app.media.cat_logo')).width(72).height(72)

七、调试技巧

  1. DevEco 资源预览resources/base/media/下的图片在 IDE 里直接预览。
  2. console.info打资源 id$r('app.media.cat_logo').id打 log,追资源加载。
  3. 图片不显示排查:检查资源名拼写;检查文件是否在media/rawfile/;检查 Image 宽高是否设。
  4. 模糊排查:1x 设备加载 3x 图会缩放模糊,补全多分辨率资源。

八、性能与最佳实践

  1. UI 图标用 $r——编译期校验、多分辨率适配免费。
  2. **Lottie/字体/大文件用rawfile**——r 不支持非标准资源。
  3. 资源名蛇形命名——驼峰会编译报错。
  4. 多分辨率准备 1x/2x/3x——避免高 dpi 设备加载低清图模糊。
  5. Image 必须设宽高——不设按原始像素渲染,可能撑爆屏幕。
  6. UI 图标 objectFit 用 Contain——保证完整不变形。

总结

本篇我们从 Image 资源引用切入,掌握了**r 编译期资源(多语言/多分辨率/暗色自动适配)**、**rawfile 原始文件(Lottie/字体/大文件)资源目录结构与命名规则三大要点,并给出了主菜单 PNG 图标改造完整代码。核心要点:r 编译期校验+多端适配;rawfile 任意文件;资源名蛇形命名;UI 图标准备 1x/2x/3x 三套**。

下一篇我们将拆解暗色模式适配——深色资源与 colorMode。

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


相关资源:

  • 「猫猫大作战」项目源码:本仓库entry/src/main/ets/pages/Index.ets
  • Image 组件官方指南
  • 资源引用 $r 与 $rawfile 官方指南
  • 资源目录结构官方文档
  • 多分辨率资源适配最佳实践
  • 开源鸿蒙跨平台社区
  • HarmonyOS 开发者官方文档首页
  • 系列索引:本仓库articles/INDEX.md

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询