# CallLibraryDemo **Repository Path**: jesob/CallLibraryDemo ## Basic Information - **Project Name**: CallLibraryDemo - **Description**: HarmonyOS API9 ArkTS(Stage模型)调用本地和npm的依赖库。 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2024-03-21 - **Last Updated**: 2024-03-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # HarmonyOS ArkTS 本地库&三方库的用法 ### 项目介绍 **项目内容:** 自定义基础组件和容器组件、依赖库概念、本地依赖库的创建和引用、三方库的引用。 **工具版本:** DevEco Studio 3.1 Canary1 **SDK版本:** 3.2.1.4(API Version 9 Canary1)(Stage模型) 本项目基于[HarmonyOS](https://developer.harmonyos.com/cn/docs/documentation/doc-guides-V3/start-overview-0000001380121578-V3)的ArkUI框架TS扩展的声明式开发范式,关于语法和概念直接看官网官方文档地址:[基于TS扩展的声明式开发范式](https://developer.harmonyos.com/cn/docs/documentation/doc-guides-V3/arkts-get-started-0000001430600477-V3), ### 效果演示 ![](image/demo.gif) ### 依赖库 实际项目中,我们会把**公共代码**或**独立功能(UI、算法....)**抽离出来封装成依赖库,提供调用方法,调用者只需将依赖库导入到项目中,使用简单的代码调用来完成开发,提高了开发效率。一般的依赖库特点:**调用简单、扩展性高。** ### 本地库 本地库主要是指未上架到npm中心,只是本地依赖使用的库。 **1、本地库的创建** a.鼠标移到工程目录顶部,鼠标右击,选择New>Module。 ![](image/demo1.png) b.在Choose Your Ability Template界面中,选择Ohos Library,点击下一步。 ![](image/demo2.png) c.在Configure the New Module界面中,配置模块信息,点击完成。 - Module name:新增模块的名称。 - Language:选择开发HarmonyOS npm包的语言。 - Device type:选择HarmonyOS npm包支持的设备类型。 - Enable Native:是否创建一个用于调用C++代码的HarmonyOS npm共享模块。 ![](image/demo3.png) **2、本地库的依赖** 在Terminal窗口中,进入模块目录中,执行如下命令进行安装,并会在package.json中自动添加依赖。 **npm install (本地模块的路径)** ``` npm install ../library ``` ![](image/demo4.png) **3、本地库的调用** 在依赖库的根目录中,index.ets文件提供了对外的导出。 ![](image/demo5.png) 在entry中index.ets页面中,引入依赖库。 ```javascript // 导入本地依赖库 import { MainPage } from '@ohos/library' @Entry @Component struct Index { build() { Column() { // 使用自定义组件 MainPage() }.width('100%').height('100%') .justifyContent(FlexAlign.Center) } } ``` ### 自定义组件 可复用的 UI 单元,可组合其它组件,被 @Component 装饰的结构体。 本项目依赖库中自定义组件:公共标题栏、侧滑菜单容器。 **1、标题栏组件** 标题自定义,左右都可以定义图标和点击事件。且左边图标有默认事件:页面返回。 ```javascript import router from '@ohos.router'; /** * 自定义标题栏 */ @Component export struct TitleBar { // 左边图标是否显示 private isShowLeft = true // 左边图标 private leftIcon = $r('app.media.back') // 左边点击事件,默认返回上一页 private leftClickEvent = () => { router.back() } // 标题 private title = '标题' // 右边图标是否显示 private isShowRight = false // 右边图标 private rightIcon = $r('app.media.icon') // 左边点击事件 private rightClickEvent: () => void build() { Column() { Stack() { Text(this.title).fontSize(20).fontColor('#ff1a1a1a') Row() { if (this.isShowLeft) { Image(this.leftIcon).size({ width: 55, height: 55 }).padding(15) .onClick(() => this.leftClickEvent()) } Blank() if (this.isShowRight) { Image(this.rightIcon).size({ width: 55, height: 55 }).padding(15) .onClick(this.rightClickEvent) } }.width('100%') }.width('100%').height(0).layoutWeight(1) Divider().color('#ffbababa') }.width('100%').height(55) } } ``` 标题栏组件的使用: ```javascript import { TitleBar } from '@ohos/library' @Entry @Component struct Index { build() { Column() { TitleBar({ title: '主页', leftIcon: $r('app.media.menu'), leftClickEvent: () => { // 左图标点击事件 } }) }.width('100%').height('100%') } } ``` **2、侧滑菜单容器** 左右滑动可以控制菜单,菜单打开时,背景透明度改变,使用动画效果打开或关闭菜单。 ```javascript /** * 滑动菜单 */ @Component export struct SlideMenuContainer { // 菜单的宽度 @State menuWidth: number = 0 // 菜单x轴偏移量 @State menuOffsetX: number = 0 // 菜单偏移最小量 private offsetXMin = 0 // 菜单偏移最大量 private offsetXMax = 0 // 第一次按下的x坐标 private firstDownX = -1 // 上次按下的x坐标 private lastDownX = -1 // 背景透明度 @State bgOpacity: number = 0 // 滑动方向 private slideDirection: 'left' | 'right' // 菜单布局 @BuilderParam menu: any // 内容布局 @BuilderParam content: any // 定时器ID private intervalID = 0 // 是否打开菜单 @Link @Watch('isOpenChanger') isOpen: boolean isOpenChanger() { if (this.isOpen) { this.openMenu() } } build() { Stack({ alignContent: Alignment.Start }) { // 内容布局 Column() { this.content() }.width('100%').height('100%') if (this.bgOpacity) { // 透明背景 Column() { }.width('100%').height('100%') .backgroundColor(Color.Black).opacity(this.bgOpacity) } // 菜单布局 Column() { this.menu() }.width(this.menuWidth).height('100%') .backgroundColor(Color.White) .offset({ x: this.menuOffsetX }) }.width('100%').height('100%') .onTouch((event) => this.onTouchEvent(event)) .onAreaChange((oldValue: Area, newValue: Area) => { // 监听回调中获取容器的宽度 const width = Number.parseInt(newValue.width.toString()) this.menuWidth = width * 0.7 this.menuOffsetX = -this.menuWidth this.offsetXMin = -this.menuWidth this.offsetXMax = 0 }) } /** * 触摸事件 */ onTouchEvent(event: TouchEvent) { const x = event.touches[0].x switch (event.type) { case TouchType.Down: // 手指按下 { this.firstDownX = x this.lastDownX = x clearInterval(this.intervalID) } break; case TouchType.Move: // 手指移动 { // 计算这次x坐标点与上次x坐标点的差 const diff = x - this.lastDownX this.lastDownX = x // 累计算出滑动的距离 this.menuOffsetX += diff // 确定方向 this.slideDirection = diff > 0 ? 'right' : 'left' // 限定距离范围 if (this.menuOffsetX >= this.offsetXMax) this.menuOffsetX = this.offsetXMax if (this.menuOffsetX <= this.offsetXMin) this.menuOffsetX = this.offsetXMin // 更改背景透明度 this.bgOpacity = 0.6 * Math.abs(this.menuWidth + this.menuOffsetX) / this.menuWidth } break; case TouchType.Up: // 手指抬起 { if (Math.abs(x - this.firstDownX) < 5) { return } if (this.slideDirection === 'left') { // 是否小于宽度的3/2 const isClose = Math.abs(this.menuWidth + this.menuOffsetX) < this.menuWidth * 2 / 3 isClose ? this.closeMenu() : this.openMenu() } else { // 是否大于宽度的3/1 const isOpen = Math.abs(this.menuWidth + this.menuOffsetX) > this.menuWidth / 3 isOpen ? this.openMenu() : this.closeMenu() } } break; default: break; } } /** * 定时器改变偏移量 * @param type 偏移量 加或减 */ intervalChangeOffset(type: 1 | -1) { this.intervalID = setInterval(() => { this.menuOffsetX += type * 15 if (this.menuOffsetX >= this.offsetXMax) { this.menuOffsetX = this.offsetXMax clearInterval(this.intervalID) } if (this.menuOffsetX <= this.offsetXMin) { this.menuOffsetX = this.offsetXMin clearInterval(this.intervalID) this.isOpen = false } this.bgOpacity = 0.6 * Math.abs(this.menuWidth + this.menuOffsetX) / this.menuWidth }, 5) } /** * 打开菜单 */ openMenu() { this.intervalChangeOffset(1) } /** * 关闭菜单 */ closeMenu() { this.intervalChangeOffset(-1) } } ``` 侧滑菜单的使用 **(部分代码)** ```javascript import { SlideMenuContainer } from '@ohos/library' @Entry @Component struct Index { @State isOpen: boolean = false ...... /** * 内容布局 */ @Builder ContentLayout() {...} /** * 菜单布局 */ @Builder MenuLayout() {...} build() { Column() { SlideMenuContainer({ isOpen: $isOpen, content: this.ContentLayout(), menu: this.MenuLayout() }) }.width('100%').height('100%') } } ``` ### 三方库 其他公司开源的库或者个人开源的库,上架到npm中心供其他开发者下载使用的库。 本项目中使用的是三方库是:lottieETS 一个适用于OpenHarmony的动画库 依赖方式和本地库一样,使用命令安装: ``` npm install @ohos/lottieETS --save ``` 以下示例只是简单用法,其他方法的使用请查看官方的文档:[lottieETS 使用说明 ](https://gitee.com/openharmony-tpc/lottieETS) ```javascript // 导入三方库 import lottie from '@ohos/lottieETS' @Entry @Component struct LottieDemo { private setting: RenderingContextSettings = new RenderingContextSettings(true) private crc: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.setting) private lottiePath = 'common/lottie/car-loading2-data.json' private lottieName = 'carName' @State isPlay: boolean = false build() { Column() { Canvas(this.crc) .width(300) .height(300) .margin({ top: 30, bottom: 50 }) .margin({ top: 30, bottom: 50 }) .onReady(() => { lottie.loadAnimation({ container: this.crc, // 需要绑定Canvas的CanvasRenderingContext2D renderer: "canvas", // 目前只支持canvas模式 loop: true, // 是否循环播放 autoplay: false, // 是否自动播放 name: this.lottieName, // 设置lottie动画名称 path: this.lottiePath // 指定lottie动画资源路径 }) }) .onDisAppear(() => { // Canvas销毁时顺带销毁lottie动画 lottie.destroy(this.lottieName) }) Button(this.isPlay ? '暂停' : '播放') .width(150).height(30) .backgroundColor('#2D9FE5') .onClick(() => { this.isPlay = !this.isPlay this.isPlay ? lottie.play(this.lottieName) : lottie.pause(this.lottieName) }) }.width('100%').height('100%') } } ``` ### **结尾** 此项目中本地库和三方库的依赖都比较简单,难点是自定义组件的使用,还是需要多看官方的文档。最后希望鸿蒙社区越来越多的人加入,创作出更多优秀三方库。 项目地址:[https://gitee.com/liangdidi/CallLibraryDemo](https://gitee.com/liangdidi/CallLibraryDemo) 每天进步一点点、需要付出努力亿点点。