#HarmonyOS NEXT体验官# 基于鸿蒙Next的App(创意工坊)解析1:相关理论和主界面设计 原创 精华
这是一系列文章,关于我的基于鸿蒙Next的App(创意工坊),这款App也是2024年鸿蒙创新大赛的入围作品(Top50),现在利用这一系列文章,详细介绍”创意工坊“App的详细制作过程,并附有核心的代码。
创意工坊是一款全面且强大的创作工具,专为满足不同用户的创意需求而设计。应用程序集成了多个高级JavaScript库,如fabric.js和gif.js,提供了一系列丰富的功能。从新建画布到自动保存和会话管理,创意工坊覆盖了整个创作流程。用户可以在创意工坊中自由绘画,插入图像和文本,并应用多种图像特效,充分释放创意潜能。文本属性和特效的设置功能允许用户进行精细的后期修改,支持删除和复制操作,确保每一个细节都能完美展现。分享和导出功能支持多种格式,包括jpg、png、svg和webp,极大地方便了创作的传播和分享。创意工坊特别值得一提的是其强大的GIF动画制作功能。用户可以利用各种特效制作帧动画,创造出栩栩如生的动画效果。这一功能满足了对动态表现有需求的用户,无论是用于社交媒体分享还是专业展示,都能轻松应对。所有这些功能的结合,使得创意工坊不仅仅是一款简单的绘图工具,而是一款功能完备的创意平台。无论是业余爱好者还是专业创作者,都能在创意工坊中找到所需的工具和灵感,进行高效而愉快的创作体验。
创意工坊采用了基于ArkWeb的混合开发技术,下面先详细介绍一下混合开发以及ArkWeb。
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,使得复杂的图形编辑和操作变得简单和直观。
主要特点:
- 矢量图形支持:Fabric.js 支持各种矢量图形,包括矩形、圆形、多边形、路径等,能够创建复杂的图形组合。
- 自由绘画:用户可以在画布上进行自由绘画,创建各种图案和线条。
- 对象操作:Fabric.js 提供了丰富的对象操作功能,如缩放、旋转、移动和变换,用户可以对图形进行多种编辑。
- 图像处理:支持导入和操作图像,用户可以对图像进行裁剪、缩放和旋转等操作。
- 文本处理:Fabric.js 支持文本对象,用户可以添加、编辑和格式化文本,包括设置字体、大小、颜色等属性。
- 事件处理:提供了丰富的事件处理机制,用户可以监听各种用户交互事件,如点击、拖动、缩放等。
- 模块化设计:Fabric.js 采用模块化设计,用户可以按需加载所需的功能模块,提高应用性能。
gif.js
gif.js 是一个用于创建和处理 GIF 动画的 JavaScript 库,旨在提供简单高效的 GIF 动画生成功能。
主要特点:
- 帧动画:gif.js 支持将多张图像帧组合成一个 GIF 动画,用户可以自由设置每一帧的显示时间。
- 图像处理:支持多种图像格式的导入,用户可以将各种图像格式转换为 GIF 动画。
- 特效支持:提供了丰富的动画特效,用户可以为每一帧添加特效,如淡入淡出、旋转、缩放等。
- 高效压缩:gif.js 采用高效的压缩算法,生成的 GIF 动画体积小,加载速度快,适合在网络环境中使用。
- 异步处理:支持异步处理,避免在生成大尺寸 GIF 动画时阻塞主线程,提高应用的响应速度。
- 易于集成: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。如下图所示。
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,具有一定的内边距和边距。
- 按钮的背景颜色可以根据不同的状态和功能进行定制。
- 每个按钮都有一个点击事件,点击后触发相应的功能。
各个按钮的功能:
- 新建按钮:切换新建面板。
- 打开按钮:打开文档列表对话框。
- 清除画板按钮:显示确认对话框,清除画布内容。
- 画板按钮:切换画板面板。
- 插入图片按钮:切换插入元素面板。
- 图像特效按钮:切换特效面板。
- 分享按钮:切换共享数据面板。
- 导出按钮:切换导出面板。
- 设置按钮:切换设置面板。
- 更多按钮:切换更多面板,默认不可见。
这些按钮被合理地安排在水平工具条中,提供了一系列便捷的操作功能,帮助用户更高效地完成各种任务。
实现效果如下图所示:
支持老师新系列!
可以点击老师头像查看更多文章
从头开始学习好文