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_MEDIAohos.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使用TabsTabContent组件实现标签页导航。我们将封装一个可复用的底部导航容器组件。

代码块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中连接真机或启动模拟器,点击运行按钮。

预期效果:

  1. 应用启动后,显示一个带有灰色标题栏"图片处理工具"的页面。
  2. 页面底部有三个Tab项:首页、编辑、我的,分别带有图标和文字。
  3. 默认选中"首页"Tab,图标和文字显示为蓝色;点击"编辑"或"我的"后,对应Tab项高亮为蓝色,其余保持灰色。
  4. 三个Tab对应的内容区域分别显示对应的文字占位"首页"“编辑”“我的”。

在这里插入图片描述

如果运行失败,请检查:

  • module.json5中权限名称是否有拼写错误
  • 图标资源文件是否放置在正确路径resources/base/media/
  • TabNavigation组件的导入路径是否正确

4. 小结与预告

本篇完成了图像处理APP的基础骨架搭建:创建了HarmonyOS工程,配置了读写媒体文件的权限,实现了底部Tab导航框架,并整合了EntryAbility与Index页面。从此刻开始,你拥有了一个可运行、可扩展的APP容器。

下一篇文章我们将正式进入图片处理功能开发的第一环:图片选择与预览。届时会使用PhotoViewPicker从系统相册选择图片,并用Image Kit的createImageSource解码图片,在编辑Tab中预览展示。准备好打开相册的大门了吗?我们第2篇再见。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐