HarmonyOS APP实战-基于Image Kit的图像处理APP - 第1篇:环境搭建与项目初始化
HarmonyOS APP实战-基于Image Kit的图像处理APP - 第1篇:环境搭建与项目创建
1. 开篇
周末的午后,你翻出手机里一张老照片,想调整一下色调、裁掉多余的部分,却发现系统相册自带的编辑功能太简单,而那些功能强大的专业修图APP不是需要付费订阅就是广告满天飞。如果能亲手打造一款属于自己的图像处理工具,把官方文档里那些“图片解码”“色彩矩阵”“像素操作”的能力都用起来,那该多好?
这正是我们接下来要一起完成的事情。本系列将基于HarmonyOS的Image Kit(图片处理服务),从零开发一个功能完整的图像处理APP。它至少包含图片选择、解码展示、缩放裁剪、旋转翻转、滤镜调色、编码导出、批量处理、水印叠加和历史记录管理等实用功能。
本篇作为整个系列的开篇,主要任务是打好地基:安装并配置DevEco Studio开发环境,创建HarmonyOS工程,配置必要的文件读写权限,并搭建底部Tab导航框架(首页、编辑、我的)。后续所有功能的开发,都将在这个骨架上生长。
2. 核心实现
2.1 基础配置:权限声明与模块导入
HarmonyOS应用的权限声明在module.json5文件中。我们要开发的APP需要读取和写入用户设备上的图片文件,因此必须声明ohos.permission.READ_MEDIA和ohos.permission.WRITE_MEDIA两个权限。
代码块1:module.json5权限配置
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": [
"phone"
],
"requestPermissions": [
{
"name": "ohos.permission.READ_MEDIA",
// 读取媒体文件权限,用于从相册选择图片
"reason": "$string:permission_read_media_reason",
// 向用户展示的权限申请理由
"usedScene": {
"abilities": [
"EntryAbility"
],
// 权限在EntryAbility中使用
"when": "always"
// 始终可用
}
},
{
"name": "ohos.permission.WRITE_MEDIA",
// 写入媒体文件权限,用于保存处理后的图片到相册
"reason": "$string:permission_write_media_reason",
"usedScene": {
"abilities": [
"EntryAbility"
],
"when": "always"
}
}
],
// ... 其他配置项
}
}
关键点说明:
requestPermissions字段用于声明应用需要申请的敏感权限。- 权限的
name必须与官方文档中定义的常量完全一致,不能拼写错误。 reason字段对应resources/base/element/string.json中的字符串资源,用于向用户解释为什么要使用该权限。usedScene用于定义权限在哪个Ability中被使用以及使用场景(前台或后台),有助于用户理解权限用途。
同时,需要在resources/base/element/string.json中添加权限申请理由的字符串资源:
{
"string": [
{
"name": "permission_read_media_reason",
"value": "用于从相册选择图片进行编辑"
},
{
"name": "permission_write_media_reason",
"value": "用于将编辑后的图片保存到相册"
}
]
}

2.2 核心逻辑:底部Tab导航组件
底部导航是大多数工具类APP的标配。HarmonyOS使用Tabs和TabContent组件实现标签页导航。我们将封装一个可复用的底部导航容器组件。
代码块2:TabNavigation组件实现(TabNavigation.ets)
/**
* TabNavigation组件
* 提供应用底部Tab导航框架
* 包含首页、编辑、我的三个标签页
*/
@Component
export struct TabNavigation {
// 当前选中的Tab索引,从0开始
@State currentIndex: number = 0
/**
* 构建页面主体
* 包含顶部的标题栏区域、中间的Tab内容区域、底部的导航栏
*/
build() {
// 使用Column实现垂直布局
Column() {
// 顶部标题栏
Row() {
Text('图片处理工具')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.width('100%')
.textAlign(TextAlign.Center)
}
.height(56)
.width('100%')
.backgroundColor('#F5F5F5')
// Tabs组件,实现标签页切换
// barPosition设置为BarPosition.End,将导航栏置于底部
Tabs({ barPosition: BarPosition.End }) {
// 首页Tab内容
// 通过TabContent嵌入首页页面
TabContent() {
// 首页内容占位,后续替换为具体页面组件
Column() {
Text('首页')
.fontSize(24)
.fontColor('#666666')
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
}
// tabBar定义导航项的外观,传入TabBarItemBuilder
.tabBar(this.buildTabItem(0, '首页', $r('app.media.ic_home')))
// 编辑Tab内容
TabContent() {
// 编辑页面占位,后续替换为图片编辑器
Column() {
Text('编辑')
.fontSize(24)
.fontColor('#666666')
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
}
.tabBar(this.buildTabItem(1, '编辑', $r('app.media.ic_edit')))
// 我的Tab内容
TabContent() {
// 我的页面占位,后续替换为个人信息或设置页
Column() {
Text('我的')
.fontSize(24)
.fontColor('#666666')
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
}
.tabBar(this.buildTabItem(2, '我的', $r('app.media.ic_user')))
}
// 监听Tab切换事件,更新currentIndex
.onChange((index: number) => {
this.currentIndex = index
})
// 设置当前激活的Tab索引
.index(this.currentIndex)
// 设置Tab导航栏的高度
.barHeight(64)
// 设置Tab导航栏的背景色
.barBackgroundColor('#FFFFFF')
.width('100%')
.height('100%')
}
.width('100%')
.height('100%')
}
/**
* 构建单个Tab项的布局
* @param index Tab项的索引
* @param label 显示的文字标签
* @param icon 图标的资源引用
* @returns 返回Column组件作为Tab项的容器
*/
@Builder
buildTabItem(index: number, label: string, icon: Resource) {
Column() {
Image(icon)
.width(24)
.height(24)
// 根据当前选中状态切换图标颜色
.fillColor(this.currentIndex === index ? Color.Blue : Color.Gray)
Text(label)
.fontSize(12)
// 根据当前选中状态切换文字颜色
.fontColor(this.currentIndex === index ? Color.Blue : Color.Gray)
.margin({ top: 4 })
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
}
}
关键点说明:
Tabs组件配合TabContent是最常用的标签页实现方式。barPosition控制导航栏位置,BarPosition.End表示底部。@Builder buildTabItem是一个自定义构建函数,用于封装重复的Tab项UI逻辑。@Builder装饰的方法可以接收参数,提升代码复用性。$r('app.media.ic_home')是资源引用的语法,需要先在resources/base/media/目录下放置对应的图标资源文件。onChange事件回调用于监听Tab切换,更新currentIndex状态,实现选中态的颜色变化。
2.3 完整页面:整合EntryAbility与Index页面
现在我们将底层的权限配置和导航组件组装到入口页面中。
代码块3:完整Index页面(pages/Index.ets)
/**
* Index页面 - 应用主入口页面
* 整合底部Tab导航组件
*/
// 导入自定义的TabNavigation组件
import { TabNavigation } from '../components/TabNavigation'
// 导入Image Kit模块,后续处理图片时需要用到
// @ohos.multimedia.image 是官方提供的图片处理核心API
import image from '@ohos.multimedia.image'
@Entry
@Component
struct Index {
// 页面构建入口
build() {
// Stack容器用于实现全屏布局
Stack() {
// 引用自定义的TabNavigation组件
TabNavigation()
.width('100%')
.height('100%')
}
.width('100%')
.height('100%')
}
}
EntryAbility.ts(AppScope/entry/src/main/ets/entryability/EntryAbility.ts):
/**
* EntryAbility - 应用主Ability
* 负责初始化窗口、设置页面加载等
*/
import AbilityConstant from '@ohos.app.ability.AbilityConstant'
import hilog from '@ohos.hilog'
import UIAbility from '@ohos.app.ability.UIAbility'
import Window from '@ohos.window'
import Want from '@ohos.app.ability.Want'
export default class EntryAbility extends UIAbility {
/**
* 当Ability创建时调用
* @param want 启动参数
* @param launchParam 启动参数
*/
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate')
}
/**
* 当Ability与窗口关联时调用
* 设置页面加载为Index页面
* @param window 当前窗口对象
*/
onWindowStageCreate(windowStage: Window.WindowStage): void {
// 加载Index页面作为主页面
windowStage.loadContent('pages/Index', (err, data) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '')
return
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '')
})
}
// ... 其他生命周期方法
}
关键点说明:
EntryAbility是应用启动时运行的第一个Ability。onWindowStageCreate方法中通过windowStage.loadContent指定应用启动后显示的第一个页面,参数为页面的路径字符串(例如'pages/Index')。import image from '@ohos.multimedia.image'导入了Image Kit核心模块。虽然本篇未使用具体图片处理API,但提前导入便于后续快速使用。- 自定义组件
TabNavigation通过import语句从相对路径导入后,可以作为普通组件直接在其他组件中使用。HarmonyOS的自定义组件具有独立的作用域,需要显式导入才能在其他文件中使用。

3. 运行验证
完成以上代码编写后,在DevEco Studio中连接真机或启动模拟器,点击运行按钮。
预期效果:
- 应用启动后,显示一个带有灰色标题栏"图片处理工具"的页面。
- 页面底部有三个Tab项:首页、编辑、我的,分别带有图标和文字。
- 默认选中"首页"Tab,图标和文字显示为蓝色;点击"编辑"或"我的"后,对应Tab项高亮为蓝色,其余保持灰色。
- 三个Tab对应的内容区域分别显示对应的文字占位"首页"“编辑”“我的”。

如果运行失败,请检查:
- module.json5中权限名称是否有拼写错误
- 图标资源文件是否放置在正确路径
resources/base/media/ - TabNavigation组件的导入路径是否正确
4. 小结与预告
本篇完成了图像处理APP的基础骨架搭建:创建了HarmonyOS工程,配置了读写媒体文件的权限,实现了底部Tab导航框架,并整合了EntryAbility与Index页面。从此刻开始,你拥有了一个可运行、可扩展的APP容器。
下一篇文章我们将正式进入图片处理功能开发的第一环:图片选择与预览。届时会使用PhotoViewPicker从系统相册选择图片,并用Image Kit的createImageSource解码图片,在编辑Tab中预览展示。准备好打开相册的大门了吗?我们第2篇再见。
更多推荐



所有评论(0)