鸿蒙应用开发的sdk 现在已经来到了5.0.2(api:14).离我上次写鸿蒙应用(那时候还是9、10)已经过去一段时间(不到一年),版本已经大跃进了,里面的大部分api都已经陌生了。
现在我因为个人兴趣写词的驱动下想要开发一个方便自己查找字典和创作的app(市面上的app只有一个《西窗烛》做了鸿蒙兼容)。预计写这个app涉及的一些功能点 我先列出来:
1. 下载网络资料(涉及网络请求下载,文件权限)
2. 个人作品本地化存储(涉及数据库操作,走sqlite3)
3. 作品海报生成 (涉及画布渲染生成以及图片存储)
4. 作品AI朗读( 涉及语言播放,AI朗读服务)
等等。要真细想,其实预想的一些功能可以充分利用鸿蒙的很酷的特性。不过我现在只想方便一下自己的兴趣,所以就不用想那么多。话不多说,我就开始先敲第一个功能:海报生成。
海报生成的功能,根据查阅一番文档下来,需要用以下功能实现,首先是canvas画布,类似html的canvas,这是一个UI组件。海报编辑器的页面肯定是以这个组件为主:
代码如下:
let settings: RenderingContextSettings = new RenderingContextSettings(true); this.context = new CanvasRenderingContext2D(settings) build() { Canvas(this.context) .width('100%').height('100%') .backgroundColor(Color.White) .onReady(() => { let bi = this.context //...code }) }
接下来我们要考虑下如何往画布上加东西。这些逻辑应该是在onready事件上完成。
画布写法跟html的差别不大。没学过的可以先用html练手,高级的画布应用也是建议先在html文件实现逻辑,待渲染逻辑稳定下来再翻译到ets去。在预览器(previewer)中是可以预览canvas渲染后的效果。
填充背景
bi.fillStyle = '#CDCDCD' bi.fillRect(0, 0, camvas.width, canvas.height)
画几何图形:
bi.fillStyle = '#CDCDCD' bi.fillRect(0, 0, 200, 150)
填写文字:
//简单渲染hello world bi.font = '30px sans-serif' bi.fillStyle ='#333'; bi.fillText("Hello World!", 20, 100)
canvas api链接:https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V14/ts-canvasrenderingcontext2d-V14
涉及的一些注意事项:
渲染图片的代码要需要注意单位转换(有内置函数px2vp)。(px => vp)
单位转换文档链接点击这里:https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V14/ts-pixel-units-V14?catalogVersion=V14
接下来是关键的地方,就是画完后画布的数据如何保存到手机上。
在安卓上图片保存是需要加入图片操作权限。鸿蒙在这一环节的细度上做出不同的创新:创建沙盒机制,最小化权限影响。
canvas的画布数据可以导出到几个不同的数据抽象类(imagedata,dataurl,image pixelmap)。
首先要在海报编辑器这一块加个按钮(这个按钮不同于普通的按钮),加个点击事件。
SaveButton({ text: SaveDescription.SAVE_IMAGE ,icon: SaveIconStyle.FULL_FILLED }).onClick(async (e:ClickEvent,result:SaveButtonOnClickResult) => { // console.log( `${JSON.stringify(result)}`) if(result == SaveButtonOnClickResult.SUCCESS){ let imgdata = this.content.getImageData() //await saveToFile( imgdata,getContext(this)) } }).offset({x:0,y:-100})
点击事件一触发就会弹出权限请求(在一定的时间内再次操作不会反复请求)。拿到用户同意的结果后 就可以进行下一步了。代码中的saveToFile函数是我自己封装。下面会介绍函数的具体代码。
最后一步就是跟文件权限有关的操作。鸿蒙系统上文件存储的机制我们需要认真了解下:具体文档链接:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V14/core-file-kit-intro-V14 。内容比较多,需要点耐心浏览。
获得用户权限后走这个自定义的函数saveToFile保存图片到文件的逻辑:
这个逻辑一次性用到3个核心包,一个是图片访问辅助,二是文件读写包,最后是图片压缩处理的包。
//引用的包 import { fileIo as fs, ReadOptions} from '@kit.CoreFileKit'; import { image } from '@kit.ImageKit'; import { photoAccessHelper } from '@kit.MediaLibraryKit'; // 请求授权图片保存到本地 export async function saveToFile(pixelMap: image.PixelMap, context: Context): Promise<void> { try { const phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context); const filePath = await phAccessHelper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'png'); const imagePacker = image.createImagePacker(); /* api版本13 以上用这个API */ const imageBuffer = await imagePacker.packToData(pixelMap, { format: 'image/png', quality: 100 }); const mode = fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE; fd = (await fs.open(filePath, mode)).fd; await fs.truncate(fd); await fs.write(fd, imageBuffer); console.log(`image buffer length as ${imageBuffer.byteLength}`) console.log( `save path as ${filePath}`); } catch (err) { hilog.error(0x0000, "utils", 'saveToFile error:', JSON.stringify(err) ?? ''); } finally { if (fd) { fs.close(fd); } } }
就可以大功告成了。完善下其他细节run一下电脑的手机模拟器,看到运行效果如自己所料成就满满。
最后我想说,上面的例子只是简单借用画布组件生成数据保存到本地的逻辑。实际中代码比这个要精深些,比如画布编辑器抽象封装(包括支持印章图片拖曳),还有渲染性能不足可以借用离线画布放在worker线程上跑,读取相册图片作为画布背景再二次加工等等。更多代码其实官方也有给代码案例(其实有一个api在最新版本不能用了,更新不算及时)
,参考链接:https://gitee.com/harmonyos_samples/watermark
其他功能我会在后续的开发中将我的开发体验感受同步到我的文章中。这个还蛮挺考验我的自律。希望大家有机会跟我一样持着“干中学,学中干”的理念,越学越废好。