前言
正所谓:Hello Word 是程序员学任何一门语言的第一个程序实践。这其实也是一个不错的正反馈,那如何让学习鸿蒙 Next 更有成就感呢?下面就演示一下从零开发一个鸿蒙 Next 版的电子木鱼,主打就是一个抽象!
实现要点
- 页面布局
- 木鱼点击
- 木鱼音效
- 动画特效
- 自定义弹窗
开始实践
页面布局
ArkTS 定义了声明式 UI 描述、自定义组件和动态扩展 UI 元素的能力,配合 ArkUI 开发框架中的系统组件及其相关的事件方法、属性方法等共同构成 UI 开发的主体。我们下面要完成的主要是一个木鱼和设置按钮、自动按钮。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| build() {
Column() { HdNav({ title: '电子木鱼', showRightIcon: false, iconColor: $r('app.color.white'), titleColor: '#ffffff' })
Row() { Text(this.woodenType[this.type] + ':'+ this.score).fontSize(22).fontColor("#ffffff").width('100%').textAlign(TextAlign.Center) }.width("100%").height("8%")
Row() { Image($r('app.media.setting')).width(25).height(25).margin(16).onClick(() => { if (this.dialogController != null) { this.dialogController.open() } }) }.width('100%')
Row() { Image($r('app.media.foreground')).width(40).height(40).margin({left:8,top:5}) }.width('100%') .onClick(() => { this.handlePopup = !this.handlePopup }) .bindPopup(this.handlePopup, { message: '数据统计功能,正在完善中~', })
Row() { if (this.isPresent) { Text(this.woodenType[this.type] + ': ' + this.woodenFishNum).fontSize(16).fontColor("#ffffff").width('100%').textAlign(TextAlign.Center) .transition(this.effect) } }.width('100%').height('25%') .alignItems(VerticalAlign.Top)
Row() { Image($r('app.media.muyu')) .width(this.isZoomed == true ? this.targetWidth * 1.2 : this.targetWidth * 1) .height(this.isZoomed == true ? this.targetHeight * 1.2 : this.targetHeight * 1) } .width('100%') .height('25%') .alignItems(VerticalAlign.Center) .justifyContent(FlexAlign.Center)
Row() { Toggle({ type: ToggleType.Switch }) .onChange((isOn: boolean) => { if(isOn) { promptAction.showToast({ message: 'auto is on.' }) } else { promptAction.showToast({ message: 'auto is off.' }) } })
Text('自动' + this.woodenType[this.type]).fontSize(18).fontColor('#ffffff').height(40).margin({left: 10})
}.width('100%').height('10%').justifyContent(FlexAlign.Center)
} .height("100%") .backgroundColor('rgba(0, 0, 0, 1.00)')
}
|
木鱼点击
木鱼是一张图片,也就是给该图绑定一个点击事件,点击一次有三个动作需要执行:
- 木鱼有放大的效果
- 有类似功德文字的飘动
- 功德数值的累加
而点击的时候要看到实时的效果,所以可以声明三个状态,通过 State 的修改,从而驱动 UI 更新,以下的 animateTo 是给域名的放大添加的一个平滑效果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| // 积分 @State score: number = 0 // 积分文字 @State isPresent: boolean = false // 木鱼是否放大 @State isZoomed: boolean = false
// 木鱼UI Image($r('app.media.muyu')) .width(this.isZoomed == true ? this.targetWidth * 1.2 : this.targetWidth * 1) .height(this.isZoomed == true ? this.targetHeight * 1.2 : this.targetHeight * 1) .onClick((event) => { animateTo({ curve: curves.springMotion() }, () => { this.isZoomed = !this.isZoomed;
if (this.isZoomed == true) { this.isPresent = true; this.score += this.woodenFishNum; this.onClickPlay(); } })
// 定时缩小/定时文字消失 setTimeout(() => {this.isZoomed = false;}, 50); setTimeout(() => {this.isPresent = false}, 600); })
|
木鱼音效
木鱼音效是点击时的咚咚的声音,这里就要使用到 HarmonyOS Next 的音频服务。这里需要注意一点,项目运行预览无法播放,一定要模拟器或真机才可以调试音频的播放效果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| // 销毁音效工具 onClickDestroy= ()=>{ AudioMgr.Ins().destroy(); console.log('audio', 'destroy'); }
// 初始化音效工具 onClickInit = ()=>{ AudioMgr.Ins().init(); console.log('audio', 'init'); }
// 播放指定音效 onClickPlay = ()=>{ AudioMgr.Ins().play(); console.log('audio', 'playing'); }
|
动画特效
这里的动画效果主要是点击木鱼,从下网上飘出一个文字然后消失的特效。在鸿蒙中可以通过 TransitionEffect 方法添加效果,首先创建特效,然后再文字上挂载。
1 2 3 4 5 6 7 8 9
| // 上移入场特效 private effect: object = TransitionEffect.OPACITY // 初始正常大小// 假设动画持续时间为500ms .combine(TransitionEffect.scale({ x: 1, y: 1 }).animation({ curve: curves.springMotion(0.6, 1.2), duration: 0 })) // 向上平移150单位// 与上一步同时开始 .combine(TransitionEffect.translate({ x: 0, y: 400 }).animation({ curve: curves.springMotion(0.6, 1.2), duration: 10000, delay: 50 })) // 淡出至完全透明// 在平移结束后开始淡出 .combine(TransitionEffect.opacity(0).animation({ curve: curves.springMotion(0.6, 1.2), duration: 1000, delay: 0 }));
|
自定义弹窗
经过前面布局,事件绑定,音效播放,一个简单的电子木鱼其实已经完成了。但是为了增添趣味和后期扩展,这里再加一个设置功能,通过按钮打开配置项弹窗,设置包括:
- 类型选项 (功德、财运、桃花运等)
- 音效选项 (各种解压的音效素材)
- 皮肤管理 (木鱼的 UI 界面设置)
- 数值修改 (对展示的累加数值做任意修改)
- 其他 (是否关闭音效,是否自动点击等)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| // 弹窗层(UI开发-组件-自定义弹窗) @CustomDialog struct SettingDialog { controller?: CustomDialogController
// 父子组件双向同步,文档见 https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-link-V5 @Link woodenFishType: number
// 木鱼敲击的数值 @Link woodenFishNum: number
build() { Column() {
Row() { Text('愿望:').fontSize(17).fontWeight(600) Radio({ value: '功德', group: 'word' }).checked(true).onChange((isChecked: boolean) => { if(isChecked) { this.woodenFishType = 0 } }) Text('功德').fontSize(15) Radio({ value: '财富', group: 'word' }).onChange((isChecked: boolean) => { if(isChecked) { this.woodenFishType = 1 } }) Text('财富').fontSize(15) Radio({ value: '桃花运', group: 'word' }).onChange((isChecked: boolean) => { if(isChecked) { this.woodenFishType = 2 } }) Text('桃花运').fontSize(15) } .width('100%') .margin({bottom: 12}) .justifyContent(FlexAlign.Start)
Row() { Text('数值:').fontSize(16).fontWeight(600) TextInput({text:'1'}).type(InputType.Number).width(180).onChange((value: string) => { this.woodenFishNum = parseInt(value) }) } .width('100%') .margin({bottom: 12}) .justifyContent(FlexAlign.Start)
Row() { Text('音效:').fontSize(16).fontWeight(600) Toggle({ type: ToggleType.Switch }) } .width('100%') .margin({bottom: 12}) .justifyContent(FlexAlign.Start)
Row() { Text('皮肤:').fontSize(16).fontWeight(600) Radio({ value: '默认', group: 'skin' }).checked(true) Text('木鱼').fontSize(15) Radio({ value: '悟空', group: 'skin' }) Text('黑悟空').fontSize(15) Radio({ value: '典韦', group: 'skin' }) Text('典韦').fontSize(15) } .width('100%') .margin({bottom: 12}) .justifyContent(FlexAlign.Start)
}.padding({top: 28, left: 15})
} }
|
这里需要注意的是:父子组件的数据传递。因为自定义弹窗和木鱼是两个不同的组件,而点击弹窗中的比如类型切换或修改的数值,全部要更新到木鱼组件的展示当中。
当然鸿蒙也提供了 @Link 装饰器,用于与其父组件中的数据源共享相同的值,可以结合上面代码和下方截图参考其用法。
写在后面
到这里,一个通用型的鸿蒙 Next 版电子木鱼就完成了。不管是组件交互还是布局都还好,唯一让我觉得不适应的是动画特效。
如果用这种方式实现电子烟花肯定不行,所以下次将换一种方法快速实现烟花秀,以及页面间的跳转,待更新~