#HarmonyOS NEXT体验官# 基于鸿蒙Next的App(创意工坊)解析1:相关理论和主界面设计 原创 精华

蒙娜丽宁
发布于 2024-7-24 21:33
浏览
1收藏

这是一系列文章,关于我的基于鸿蒙Next的App(创意工坊),这款App也是2024年鸿蒙创新大赛的入围作品(Top50),现在利用这一系列文章,详细介绍”创意工坊“App的详细制作过程,并附有核心的代码。


创意工坊是一款全面且强大的创作工具,专为满足不同用户的创意需求而设计。应用程序集成了多个高级JavaScript库,如fabric.js和gif.js,提供了一系列丰富的功能。从新建画布到自动保存和会话管理,创意工坊覆盖了整个创作流程。用户可以在创意工坊中自由绘画,插入图像和文本,并应用多种图像特效,充分释放创意潜能。


文本属性和特效的设置功能允许用户进行精细的后期修改,支持删除和复制操作,确保每一个细节都能完美展现。分享和导出功能支持多种格式,包括jpg、png、svg和webp,极大地方便了创作的传播和分享。创意工坊特别值得一提的是其强大的GIF动画制作功能。用户可以利用各种特效制作帧动画,创造出栩栩如生的动画效果。这一功能满足了对动态表现有需求的用户,无论是用于社交媒体分享还是专业展示,都能轻松应对。


所有这些功能的结合,使得创意工坊不仅仅是一款简单的绘图工具,而是一款功能完备的创意平台。无论是业余爱好者还是专业创作者,都能在创意工坊中找到所需的工具和灵感,进行高效而愉快的创作体验。


创意工坊采用了基于ArkWeb的混合开发技术,下面先详细介绍一下混合开发以及ArkWeb。


#HarmonyOS NEXT体验官# 基于鸿蒙Next的App(创意工坊)解析1:相关理论和主界面设计-鸿蒙开发者社区

1. 基于Web的混合开发

基于Web的混合开发是一种应用程序开发方式,它结合了Web技术(如HTML、CSS和JavaScript)与原生应用开发技术。混合开发模式下,开发者可以利用Web技术来构建应用的用户界面,同时利用原生代码来实现性能关键的功能。


混合开发的几遍原理是通过将Web应用嵌入到一个原生应用中来实现。这种方式通常使用一个内置的Web视图(WebView)组件来加载和显示Web内容。应用的界面和交互逻辑通过Web技术实现,而底层的系统功能(如访问硬件设备、文件系统等)通过原生代码实现。常见的混合开发框架包括Apache Cordova、Ionic和React Native等。主要优势如下:

(1)跨平台性:由于Web技术本身是跨平台的,使用混合开发可以同时支持多种操作系统,如Android、iOS和HarmonyOS。

(2)开发效率高:使用HTML、CSS和JavaScript等Web技术进行开发,相比于传统的原生开发,能够提高开发效率,减少开发成本。

(3)热更新:应用可以通过服务器端直接更新Web内容,无需重新发布应用。


2.ArkWeb

ArkWeb是鸿蒙系统中用于支持基于Web技术的混合开发的组件。它提供了一个强大的WebView,使得Web内容可以嵌入到鸿蒙应用中。ArkWeb不仅支持常见的HTML、CSS和JavaScript技术,还提供了一些特定的接口,允许Web应用访问鸿蒙系统的原生功能。


3. 创意工坊用了什么技术

创意工坊除了使用鸿蒙相关技术外,还使用了fabric.js和gif.js。下面分别介绍一下这两个库:


Fabric.js

Fabric.js 是一个强大的 JavaScript 库,专门用于处理 HTML5 画布(canvas)的图形操作。它为开发者提供了一套丰富的 API,使得复杂的图形编辑和操作变得简单和直观。


主要特点:

  1. 矢量图形支持:Fabric.js 支持各种矢量图形,包括矩形、圆形、多边形、路径等,能够创建复杂的图形组合。
  2. 自由绘画:用户可以在画布上进行自由绘画,创建各种图案和线条。
  3. 对象操作:Fabric.js 提供了丰富的对象操作功能,如缩放、旋转、移动和变换,用户可以对图形进行多种编辑。
  4. 图像处理:支持导入和操作图像,用户可以对图像进行裁剪、缩放和旋转等操作。
  5. 文本处理:Fabric.js 支持文本对象,用户可以添加、编辑和格式化文本,包括设置字体、大小、颜色等属性。
  6. 事件处理:提供了丰富的事件处理机制,用户可以监听各种用户交互事件,如点击、拖动、缩放等。
  7. 模块化设计:Fabric.js 采用模块化设计,用户可以按需加载所需的功能模块,提高应用性能。


gif.js

gif.js 是一个用于创建和处理 GIF 动画的 JavaScript 库,旨在提供简单高效的 GIF 动画生成功能。


主要特点:

  1. 帧动画:gif.js 支持将多张图像帧组合成一个 GIF 动画,用户可以自由设置每一帧的显示时间。
  2. 图像处理:支持多种图像格式的导入,用户可以将各种图像格式转换为 GIF 动画。
  3. 特效支持:提供了丰富的动画特效,用户可以为每一帧添加特效,如淡入淡出、旋转、缩放等。
  4. 高效压缩:gif.js 采用高效的压缩算法,生成的 GIF 动画体积小,加载速度快,适合在网络环境中使用。
  5. 异步处理:支持异步处理,避免在生成大尺寸 GIF 动画时阻塞主线程,提高应用的响应速度。
  6. 易于集成:gif.js 设计简洁,易于集成到各种 Web 应用中,用户可以方便地使用它来生成和处理 GIF 动画。


应用中的具体使用

在创意工坊中,Fabric.js 被用来实现画布的绘制和编辑功能。用户可以通过它进行自由绘画、插入图像和文本,并对这些元素进行各种操作,如缩放、旋转和变换。此外,Fabric.js 的事件处理机制使得用户能够直观地与画布进行交互,提升了用户体验。


gif.js 则被用于生成和处理 GIF 动画。用户可以在创意工坊中创建帧动画,并为每一帧设置不同的特效和显示时间。gif.js 的高效压缩和异步处理特性确保了生成的 GIF 动画体积小、加载快,同时不会影响应用的整体性能。


通过将 Fabric.js 和 gif.js 结合使用,创意工坊实现了强大的图形处理和动画制作功能,为用户提供了一个功能完备且易于使用的创作平台。


4. 基于Web的混合开发

在鸿蒙中,集成js库非常容易,只需要将这两个库放到resources/rawfile目录中即可。本例会在rawfile目录分别创建了gifstudio和photo_studio子目录,分别放置gif.js和fabric.js。如下图所示。


#HarmonyOS NEXT体验官# 基于鸿蒙Next的App(创意工坊)解析1:相关理论和主界面设计-鸿蒙开发者社区


5. 设计app的主界面

主界面采用ArkUI实现,具体的绘画使用Web组件实现。ArkUI的代码需要放到主程序(index.ets)的build方法中,代码如下:


Column() { // 主垂直布局容器
  Row({ space: 5 }) { // 水平布局容器,子元素之间间距为5
    Button({ type: ButtonType.Normal }) { // 新建按钮
      Column() { // 按钮内部的垂直布局
        Image($r('app.media.new')).width(16).height(16) // 按钮图标
        Text($r('app.string.new')) // 按钮文本
          .fontSize(10) // 文本字体大小
          .fontColor(0xffffff) // 文本字体颜色
          .fontWeight(FontWeight.Bold) // 文本字体粗细
          .margin({ top: 4 }) // 文本上边距
      }
    }
    .width(36) // 按钮宽度
    .height(36) // 按钮高度
    .borderRadius(8) // 按钮圆角半径
    .padding({ top: 3, bottom: 3 }) // 按钮上下内边距
    .margin({ bottom: 4 }) // 按钮下边距
    .backgroundColor(this.newButtonBackgroundColor) // 按钮背景颜色
    .onClick(() => { // 按钮点击事件
      this.toggleNewPanel(); // 切换新建面板
    })

    Button({ type: ButtonType.Normal }) { // 打开按钮
      Column() {
        Image($r('app.media.open')).width(16).height(16)
        Text($r('app.string.open'))
          .fontSize(10)
          .fontColor(0xffffff)
          .fontWeight(FontWeight.Bold)
          .margin({ top: 4 })
      }
    }
    .width(36)
    .height(36)
    .backgroundColor($r('app.color.statusbar_background'))
    .padding({ top: 3, bottom: 3 })
    .margin({ bottom: 4 })
    .onClick(() => {
      this.saveDocumentFlag = false; // 设置保存文档标志为 false
      this.documentListDialogController.open(); // 打开文档列表对话框
    })

    Button({ type: ButtonType.Normal }) { // 清除画板按钮
      Column() {
        Image($r('app.media.clear_drawing_board')).width(16).height(16)
        Text($r('app.string.clear_drawing_board'))
          .fontSize(10)
          .fontColor(0xffffff)
          .fontWeight(FontWeight.Bold)
          .margin({ top: 4 })
      }
    }
    .width(36)
    .height(36)
    .backgroundColor($r('app.color.statusbar_background'))
    .padding({ top: 3, bottom: 3 })
    .margin({ bottom: 4 })
    .onClick(() => {
      if(this.currentDocumentName === '') { // 如果当前文档名为空,则返回
        return;
      }
      AlertDialog.show({ // 显示警告对话框
        message:'是否清除画板的内容?', // 对话框消息
        alignment: DialogAlignment.Center, // 对话框居中对齐
        primaryButton: { // 确定按钮
          value: '确定',
          action: () => {
            this.controller1.runJavaScript(`clearCanvas()`); // 调用 JavaScript 清除画布内容
          }
        },
        secondaryButton: { // 取消按钮
          value: '取消',
          action: () => { }
        }
      })
    })

    Button({ type: ButtonType.Normal }) { // 画板按钮
      Column() {
        Image($r('app.media.drawing_board')).width(16).height(16)
        Text($r('app.string.drawing_board'))
          .fontSize(10)
          .fontColor(0xffffff)
          .fontWeight(FontWeight.Bold)
          .margin({ top: 4 })
      }
    }
    .width(36)
    .height(36)
    .backgroundColor(this.drawingBoardButtonBackgroundColor)
    .padding({ top: 3, bottom: 3 })
    .margin({ bottom: 4 })
    .onClick(() => {
      if(this.currentDocumentName === '') {
        return;
      }
      this.toggleDrawingBoardPanel(); // 切换画板面板
    })

    Button({ type: ButtonType.Normal }) { // 插入图片按钮
      Column() {
        Image($r('app.media.insert_image')).width(16).height(16)
        Text($r('app.string.insert'))
          .fontSize(10)
          .fontColor(0xffffff)
          .fontWeight(FontWeight.Bold)
          .margin({ top: 4 })
      }
    }
    .width(36)
    .height(36)
    .backgroundColor(this.insertElementsButtonBackgroundColor)
    .padding({ top: 3, bottom: 3 })
    .margin({ bottom: 4 })
    .onClick(() => {
      if(this.currentDocumentName === '') {
        return;
      }
      this.toggleInsertElementsPanel(); // 切换插入元素面板
    })

    Button({ type: ButtonType.Normal }) { // 图像特效按钮
      Column() {
        Image($r('app.media.image_effects')).width(16).height(16)
        Text($r('app.string.image_effects'))
          .fontSize(10)
          .fontColor(0xffffff)
          .fontWeight(FontWeight.Bold)
          .margin({ top: 4 })
      }
    }
    .width(36)
    .height(36)
    .backgroundColor(this.effectsButtonBackgroundColor)
    .padding({ top: 3, bottom: 3 })
    .margin({ bottom: 4 })
    .onClick(() => {
      if(this.currentDocumentName === '') {
        return;
      }
      this.toggleEffectsPanel(); // 切换特效面板
    })

    Button({ type: ButtonType.Normal }) { // 分享按钮
      Column() {
        Image($r('app.media.share')).width(16).height(16)
        Text($r('app.string.share'))
          .fontSize(10)
          .fontColor(0xffffff)
          .fontWeight(FontWeight.Bold)
          .margin({ top: 4 })
      }
    }
    .width(36)
    .height(36)
    .backgroundColor(this.sharedDataButtonBackgroundColor)
    .margin({ bottom: 4 })
    .padding({ top: 3, bottom: 3 })
    .onClick(() => {
      if(this.currentDocumentName === '') {
        return;
      }
      this.toggleSharedDataPanel(); // 切换共享数据面板
    })

    Button({ type: ButtonType.Normal }) { // 导出按钮
      Column() {
        Image($r('app.media.export')).width(16).height(16)
        Text($r('app.string.export'))
          .fontSize(10)
          .fontColor(0xffffff)
          .fontWeight(FontWeight.Bold)
          .margin({ top: 4 })
      }
    }
    .width(36)
    .height(36)
    .margin({ bottom: 4 })
    .backgroundColor(this.exportButtonBackgroundColor)
    .padding({ top: 3, bottom: 3 })
    .onClick(() => {
      if(this.currentDocumentName === '') {
        return;
      }
      this.toggleExportPanel(); // 切换导出面板
    })

    Button({ type: ButtonType.Normal }) { // 设置按钮
      Column() {
        Image($r('app.media.settings')).width(16).height(16)
        Text($r('app.string.settings'))
          .fontSize(10)
          .fontColor(0xffffff)
          .fontWeight(FontWeight.Bold)
          .margin({ top: 4 })
      }
    }
    .width(36)
    .height(36)
    .margin({ bottom: 4 })
    .backgroundColor(this.settingsButtonBackgroundColor)
    .padding({ top: 3, bottom: 3 })
    .onClick(() => {
      if(this.currentDocumentName === '') {
        return;
      }
      this.toggleSettingsPanel(); // 切换设置面板
    })

    Button({ type: ButtonType.Normal }) { // 更多按钮
      Column() {
        Image($r('app.media.more')).width(16).height(16)
        Text($r('app.string.more'))
          .fontSize(10)
          .fontColor(0xffffff)
          .fontWeight(FontWeight.Bold)
          .margin({ top: 4 })
      }
    }
    .visibility(Visibility.None) // 按钮默认不可见
    .width(36)
    .height(36)
    .margin({ bottom: 4 })
    .backgroundColor(this.moreButtonBackgroundColor)
    .padding({ top: 3, bottom: 3 })
    .onClick(() => {
      if(this.currentDocumentName === '') {
        return;
      }
      this.toggleMorePanel(); // 切换更多面板
    })
  }.backgroundStyle() // 设置背景样式
  .justifyContent(FlexAlign.Start) // 水平对齐方式:开始
  .alignItems(VerticalAlign.Center) // 垂直对齐方式:居中
}


该代码段定义了一个包含多个按钮的水平工具条。每个按钮具有不同的功能,包括新建、打开、清除画板、显示画板、插入图片、应用特效、分享、导出、设置和更多功能。这些按钮被放置在一个水平布局的 Row 容器中,每个按钮内部使用 Column 容器进行垂直排列。


按钮的共同特性:

  • 每个按钮都使用了 Button 组件,并且类型设置为 ButtonType.Normal。
  • 按钮内包含一个图标(使用 Image 组件)和一个文本标签(使用 Text 组件),这些组件在垂直方向上排列。
  • 按钮的大小统一设置为宽度 36、高度 36,具有一定的内边距和边距。
  • 按钮的背景颜色可以根据不同的状态和功能进行定制。
  • 每个按钮都有一个点击事件,点击后触发相应的功能。


各个按钮的功能:

  • 新建按钮:切换新建面板。
  • 打开按钮:打开文档列表对话框。
  • 清除画板按钮:显示确认对话框,清除画布内容。
  • 画板按钮:切换画板面板。
  • 插入图片按钮:切换插入元素面板。
  • 图像特效按钮:切换特效面板。
  • 分享按钮:切换共享数据面板。
  • 导出按钮:切换导出面板。
  • 设置按钮:切换设置面板。
  • 更多按钮:切换更多面板,默认不可见。


这些按钮被合理地安排在水平工具条中,提供了一系列便捷的操作功能,帮助用户更高效地完成各种任务。


实现效果如下图所示:


#HarmonyOS NEXT体验官# 基于鸿蒙Next的App(创意工坊)解析1:相关理论和主界面设计-鸿蒙开发者社区

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2024-9-13 16:58:14修改
3
收藏 1
回复
举报
4条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

支持老师新系列!

1
回复
2024-7-25 10:08:17
红叶亦知秋
红叶亦知秋

可以点击老师头像查看更多文章

回复
2024-7-31 17:21:01
真庐山升龙霸
真庐山升龙霸

从头开始学习好文

回复
2024-8-14 14:38:55
牧南牧南
牧南牧南

系列文章真不错

回复
2024-9-13 17:01:35
回复
    相关推荐