(以下内容来自开发者分享,不代表 OpenHarmony 项目群工作委员会观点)

邢碌

上一章我们讲解了应用编译环境准备,设备编译环境准备,开发板烧录,将一个最简单的 OpenAtom OpenHarmony(以下简称“OpenHarmony”)程序安装到我们的标准设备上。

本章是 OpenHarmony 标准设备应用开发的第二篇文章。我们通过知识体系新开发的几个基于 OpenHarmony3.1 Beta 标准系统的样例:分布式音乐播放、传炸弹、购物车等样例,分别介绍下音乐播放、显示动画、动画转场(页面间转场)三个进阶技能。首先我们来讲如何在 OpenHarmony 中实现音乐的播放。

一、分布式音乐播放

通过分布式音乐播放器,大家可以学到一些 ArkUI 组件和布局在 OpenHarmony 中是如何使用的,以及如何在自己的应用中实现音乐的播放,暂停等相关功能。应用效果如下图所示:

1.1 界面布局

整体布局效果如下图所示:

 代码参考链接 :https://gitee.com/openharmony-sig/knowledge_demo_temp/blob/master/FA/Entertainment/DistrubutedMusicPlayer/entry/src/main/ets/MainAbility/pages/index.ets

首先是页面整体布局,部分控件是以模块的方式放在整体布局中的,如 operationPannel()、sliderPannel()、playPannel() 模块。页面整体布是由 Flex 控件中,包含 Image、Text 以及刚才所说的三个模块所构成。

  1. build() {
  2. Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceBetween }) {
  3. Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }) {
  4. Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.End }) {
  5. Image($r("app.media.icon_liuzhuan")).width(32).height(32)
  6. }.padding({ right: 32 }).onClick(() => {
  7. this.onDistributeDevice()
  8. })
  9.  
  10. Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.Center }) {
  11. Image($r("app.media.Bg_classic")).width(312).height(312)
  12. }.margin({ top: 24 })
  13.  
  14. Text(this.currentMusic.name).fontSize(20).fontColor("#e6000000").margin({ top: 10 })
  15. Text("未知音乐家").fontSize(14).fontColor("#99000000").margin({ top: 10 })
  16. }.flexGrow(1)
  17.  
  18. Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.End }) {
  19. this.operationPannel()
  20. this.sliderPannel()
  21. this.playPannel()
  22. }.height(200)
  23. }
  24. .linearGradient({
  25. angle: 0,
  26. direction: GradientDirection.Bottom,
  27. colors: this.currentMusic.backgourdColor
  28. }).padding({ top: 48, bottom: 24, left: 24, right: 24 })
  29. .width('100%')
  30. .height('100%')
  31. }

operationPannel() 模块的布局,该部分代码对应图片中的心形图标,下载图标,评论图标更多图标这一部分布局。其主要是在 Flex 中包含 Image 所构成代码如下:

  1. @Builder operationPannel() {
  2. Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceBetween }) {
  3. Image($r("app.media.icon_music_like")).width(24).height(24)
  4. Image($r("app.media.icon_music_download")).width(24).height(24)
  5. Image($r("app.media.icon_music_comment")).width(24).height(24)
  6. Image($r("app.media.icon_music_more")).width(24).height(24)
  7. }.width('100%').height(49).padding({ bottom: 25 })
  8. }

sliderPannel() 模块代码布局。该部分对应图片中的显示播放时间那一栏的控件。整体构成是在 Flex 中,包含 Text、Slider、Text 三个控件。具体代码如下:

  1. @Builder sliderPannel() {
  2. Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
  3. Text(this.currentTimeText).fontSize(12).fontColor("ff000000").width(40)
  4. Slider({
  5. value: this.currentProgress,
  6. min: 0,
  7. max: 100,
  8. step: 1,
  9. style: SliderStyle.INSET
  10. })
  11. .blockColor(Color.White)
  12. .trackColor(Color.Gray)
  13. .selectedColor(Color.Blue)
  14. .showSteps(true)
  15. .flexGrow(1)
  16. .margin({ left: 5, right: 5 })
  17. .onChange((value: number, mode: SliderChangeMode) => {
  18. if (mode == 2) {
  19. CommonLog.info('aaaaaaaaaaaaaa1: ' + this.currentProgress)
  20. this.onChangeMusicProgress(value, mode)
  21. }
  22. })
  23.  
  24. Text(this.totalTimeText).fontSize(12).fontColor("ff000000").width(40)
  25.  
  26. }.width('100%').height(18)
  27. }

playPannel() 模块代码对应图片中的最底部播放那一栏五个图标所包含的一栏。整体布局是 Flex 方向为横向,其中包含五个 Image 所构成。具体代码如下:

  1. @Builder playPannel() {
  2. Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceBetween }) {
  3. Image($r("app.media.icon_music_changemode")).width(24).height(24).onClick(() => {
  4. this.onChangePlayMode()
  5. })
  6. Image($r("app.media.icon_music_left")).width(32).height(32).onClick(() => {
  7. this.onPreviousMusic()
  8. })
  9. Image(this.isPlaying ? $r("app.media.icon_music_play") : $r("app.media.icon_music_stop"))
  10. .width(80)
  11. .height(82)
  12. .onClick(() => {
  13. this.onPlayOrPauseMusic()
  14. })
  15. Image($r("app.media.icon_music_right")).width(32).height(32).onClick(() => {
  16. this.onNextMusic()
  17. })
  18. Image($r("app.media.icon_music_list")).width(24).height(24).onClick(() => {
  19. this.onShowMusicList()
  20. })
  21. }.width('100%').height(82)
  22. }

希望通过上面这些布局的演示,可以让大家学到一些部分控件在 OpenHarmony 中的运用,这里使用的 Arkui 布局和 HarmonyOS* 是一致的,目前 HarmonyOS* 手机还没有发布 Arkui 的版本,大家可以在 OpenHarmony 上抢先体验。常用的布局和控件还有很多,大家可以在下面的链接中找到更多的详细信息。

*编者注:HarmonyOS 是基于开放原子开源基金会旗下开源项目 OpenHarmony 开发的面向多种全场景智能设备的商用版本。是结合其自有特性和能力开发的新一代智能终端操作系统。

官网参考链接:https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components.md

1.2 播放音乐

  1. play(seekTo) {
  2. if (this.player.state == 'playing' && this.player.src == this.getCurrentMusic().url) {
  3. return
  4. }
  5.  
  6. if (this.player.state == 'idle' || this.player.src != this.getCurrentMusic().url) {
  7. CommonLog.info('Preload music url = ' + this.getCurrentMusic().url)
  8. this.player.reset()
  9. this.player.src = this.getCurrentMusic().url
  10. this.player.on('dataLoad', () => {
  11. CommonLog.info('dataLoad duration=' + this.player.duration)
  12. this.totalTimeMs = this.player.duration
  13. if (seekTo > this.player.duration) {
  14. seekTo = -1
  15. }
  16. this.player.on('play', (err, action) => {
  17. if (err) {
  18. CommonLog.info(`MusicPlayer[PlayerModel] error returned in play() callback`)
  19. return
  20. }
  21. if (seekTo > 0) {
  22. this.player.seek(seekTo)
  23. }
  24. })
  25.  
  26. this.player.play()
  27. this.statusChangeListener()
  28. this.setProgressTimer()
  29. this.isPlaying = true
  30. })
  31. }
  32. else {
  33. if (seekTo > this.player.duration) {
  34. seekTo = -1
  35. }
  36. this.player.on('play', (err, action) => {
  37. if (err) {
  38. CommonLog.info(`MusicPlayer[PlayerModel] error returned in play() callback`)
  39. return
  40. }
  41. if (seekTo > 0) {
  42. this.player.seek(seekTo)
  43. }
  44. })
  45.  
  46. this.player.play()
  47. this.setProgressTimer()
  48. this.isPlaying = true
  49. }
  50. }

1.3 音乐暂停

  1. pause() {
  2. CommonLog.info("pause music")
  3. this.player.pause();
  4. this.cancelProgressTimer()
  5. this.isPlaying = false
  6. }

具体代码:https://gitee.com/openharmony-sig/knowledge_demo_temp/blob/master/FA/Entertainment/DistrubutedMusicPlayer/entry/src/main/ets/Common/PlayerManager.ets

分布式音乐播放器项目下载链接:https://gitee.com/openharmony-sig/knowledge_demo_temp/tree/master/FA/Entertainment/DistrubutedMusicPlayer

接下来我们讲解如何在 OpenHarmony 中实现显示动画的效果。

二、显示动画

我们以传炸弹小游戏中的显示动画效果为例,效果如下图所示。

通过本小节,大家在上一小节的基础上,学到更多 ArkUI 组件和布局在 OpenHarmony 中的应用,以及如何在自己的应用中实现显示动画的效果。

代码链接:https://gitee.com/openharmony-sig/knowledge_demo_temp/blob/master/FA/Entertainment/BombGame/entry/src/main/ets/MainAbility/pages/game.ets

实现步骤:

2.1 编写弹窗布局:将游戏失败文本、炸弹图片和再来一局按钮图片放置于 Column 容器中;

2.2 用变量来控制动画起始和结束的位置:用 Flex 容器包裹炸弹图片,并用 @State 装饰变量 toggle,通过变量来动态修改 Flex 的 direction 属性;布局代码如下:

  1. @State toggle: boolean = true
  2. private controller: CustomDialogController
  3. @Consume deviceList: RemoteDevice[]
  4. private confirm: () => void
  5. private interval = null
  6.  
  7. build() {
  8. Column() {
  9. Text('游戏失败').fontSize(30).margin(20)
  10. Flex({
  11. direction: this.toggle ? FlexDirection.Column : FlexDirection.ColumnReverse,
  12. alignItems: ItemAlign.Center
  13. })
  14. {
  15. Image($r("app.media.bomb")).objectFit(ImageFit.Contain).height(80)
  16. }.height(200)
  17.  
  18. Image($r("app.media.btn_restart")).objectFit(ImageFit.Contain).height(120).margin(10)
  19. .onClick(() => {
  20. this.controller.close()
  21. this.confirm()
  22. })
  23. }
  24. .width('80%')
  25. .margin(50)
  26. .backgroundColor(Color.White)
  27. }

2.3 设置动画效果:使用 animateTo 显式动画接口炸弹位置切换时添加动画,并且设置定时器定时执行动画,动画代码如下:

  1. aboutToAppear() {
  2. this.setBombAnimate()
  3. }
  4.  
  5. setBombAnimate() {
  6. let fun = () => {
  7. this.toggle = !this.toggle;
  8. }
  9. this.interval = setInterval(() => {
  10. animateTo({ duration: 1500, curve: Curve.Sharp }, fun)
  11. }, 1600)
  12. }

项目下载链接:https://gitee.com/openharmony-sig/knowledge_demo_temp/tree/master/FA/Entertainment/BombGame

三、转场动画(页面间转场)

我们同样希望在本小节中,可以让大家看到更多的 ArkUI 中的组件和布局在 OpenHarmony 中的使用,如何模块化的使用布局,让自己的代码更简洁易读,以及在应用中实现页面间的转场动画效果。

下图是分布式购物车项目中的转场动画效果图:

代码参考链接:https://gitee.com/openharmony-sig/knowledge_demo_temp/blob/master/FA/Shopping/DistributedShoppingCart/entry/src/main/ets/MainAbility/pages/HomePage.ets

页面布局效果图:

整体布局由 Column、Scroll、Flex、Image 以及 GoodsHome()、MyInfo()、HomeBottom() 构成,该三个模块我们会分别说明。具体代码如下:

  1. build() {
  2. Column() {
  3. Scroll() {
  4. Column() {
  5. if (this.currentPage == 1) {
  6. Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.End }) {
  7. Image($r("app.media.icon_share"))
  8. .objectFit(ImageFit.Cover)
  9. .height('60lpx')
  10. .width('60lpx')
  11. }
  12. .width("100%")
  13. .margin({ top: '20lpx', right: '50lpx' })
  14. .onClick(() => {
  15. this.playerDialog.open()
  16. })
  17.  
  18. GoodsHome({ goodsItems: this.goodsItems})
  19. }
  20. else if (this.currentPage == 3) {
  21. //我的
  22. MyInfo()
  23. }
  24. }
  25. .height('85%')
  26. }
  27. .flexGrow(1)
  28.  
  29. HomeBottom({ remoteData: this.remoteData})
  30.  
  31. }
  32. .backgroundColor("white")
  33. }

GoodsHome() 模块对应效果图中间显示商品的部分,其主要结构为 TabContent 中包含的两个 List 条目所构成。具体代码如下:

  1. @Component
  2. struct GoodsHome {
  3. private goodsItems: GoodsData[]
  4. @Consume ShoppingCartsGoods :any[]
  5. build() {
  6. Column() {
  7. Tabs() {
  8. TabContent() {
  9. GoodsList({ goodsItems: this.goodsItems});
  10. }
  11. .tabBar("畅销榜")
  12. .backgroundColor(Color.White)
  13.  
  14. TabContent() {
  15. GoodsList({ goodsItems: this.goodsItems});
  16. }
  17. .tabBar("推荐")
  18. .backgroundColor(Color.White)
  19. }
  20. .barWidth(500)
  21. .barHeight(50)
  22. .scrollable(true)
  23. .barMode(BarMode.Scrollable)
  24. .height('980lpx')
  25.  
  26. }
  27. .alignItems(HorizontalAlign.Start)
  28. .width('100%')
  29. }
  30. }

上面代码中的 GoodsList() 为每个 list 条目对应显示的信息,会便利集合中的数据,然后显示在对用的 item 布局中,具体代码如下:

  1. @Component
  2. struct GoodsList {
  3. private goodsItems: GoodsData[]
  4. @Consume ShoppingCartsGoods :any[]
  5. build() {
  6. Column() {
  7. List() {
  8. ForEach(this.goodsItems, item => {
  9. ListItem() {
  10. GoodsListItem({ goodsItem: item})
  11. }
  12. }, item => item.id.toString())
  13. }
  14. .width('100%')
  15. .align(Alignment.Top)
  16. .margin({ top: '10lpx' })
  17. }
  18. }
  19. }

最后就是 list 的 item 布局代码。具体代码如下:

  1. @Component
  2. struct GoodsListItem {
  3. private goodsItem: GoodsData
  4. @State scale: number = 1
  5. @State opacity: number = 1
  6. @State active: boolean = false
  7. @Consume ShoppingCartsGoods :any[]
  8. build() {
  9. Column() {
  10. Navigator({ target: 'pages/DetailPage' }) {
  11. Row({ space: '40lpx' }) {
  12. Column() {
  13. Text(this.goodsItem.title)
  14. .fontSize('28lpx')
  15. Text(this.goodsItem.content)
  16. .fontSize('20lpx')
  17. Text('¥' + this.goodsItem.price)
  18. .fontSize('28lpx')
  19. .fontColor(Color.Red)
  20. }
  21. .height('160lpx')
  22. .width('50%')
  23. .margin({ left: '20lpx' })
  24. .alignItems(HorizontalAlign.Start)
  25.  
  26. Image(this.goodsItem.imgSrc)
  27. .objectFit(ImageFit.ScaleDown)
  28. .height('160lpx')
  29. .width('40%')
  30. .renderMode(ImageRenderMode.Original)
  31. .margin({ right: '20lpx', left: '20lpx' })
  32.  
  33. }
  34. .height('180lpx')
  35. .alignItems(VerticalAlign.Center)
  36. .backgroundColor(Color.White)
  37. }
  38. .params({ goodsItem: this.goodsItem ,ShoppingCartsGoods:this.ShoppingCartsGoods})
  39. .margin({ left: '40lpx' })
  40. }
  41. }

备注:MyInfo() 模块对应的事其它也免得布局,这里就不做说明。

最后我们来说一下,页面间的页面间的转场动画,其主要是通过在全局 pageTransition 方法内配置页面入场组件和页面退场组件来自定义页面转场动效。具体代码如下:

  1. // 转场动画使用系统提供的多种默认效果(平移、缩放、透明度等)
  2. pageTransition() {
  3. PageTransitionEnter({ duration: 1000 })
  4. .slide(SlideEffect.Left)
  5. PageTransitionExit({ duration: 1000 })
  6. .slide(SlideEffect.Right)
  7. }
  8. }

项目下载链接地址:https://gitee.com/openharmony-sig/knowledge_demo_temp/tree/master/FA/Shopping/DistributedShoppingCart

官网参考链接:https://gitee.com/openharmony/docs/blob/OpenHarmony-3.1-Beta/zh-cn/application-dev/reference/arkui-ts/ts-page-transition-animation.md

通过上述讲解,我们就在自己的代码中实现音乐的播放,显示动画,页面间转场动画等效果。

在接下来的一章中,我们会讲解如何在 OpenHarmony 通过分布式数据管理,实现设备之间数据如何同步刷新。

OpenHarmony标准设备应用开发(二)——布局、动画与音乐的更多相关文章

  1. OpenHarmony标准设备应用开发(三)——分布式数据管理

    (以下内容来自开发者分享,不代表 OpenHarmony 项目群工作委员会观点) 邢碌 上一章,我们通过分布式音乐播放器.分布式炸弹.分布式购物车,带大家讲解了 OpenAtom OpenHarmon ...

  2. OpenHarmony标准设备应用开发(一)——HelloWorld

    (以下内容来自开发者分享,不代表 OpenHarmony 项目群工作委员会观点) 邢碌 本文是 OpenAtom OpenHarmony(以下简称"OpenHarmony")标准设 ...

  3. Android动画效果之自定义ViewGroup添加布局动画

    前言: 前面几篇文章介绍了补间动画.逐帧动画.属性动画,大部分都是针对View来实现的动画,那么该如何为了一个ViewGroup添加动画呢?今天结合自定义ViewGroup来学习一下布局动画.本文将通 ...

  4. IOS开发系列 --- 核心动画

    原始地址:http://www.cnblogs.com/kenshincui/p/3972100.html 概览 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥i ...

  5. 动画_ _ Android应用开发之所有动画使用详解

    转载: http://blog.csdn.net/yanbober/article/details/46481171 题外话:有段时间没有更新博客了,这篇文章也是之前写了一半一直放在草稿箱,今天抽空把 ...

  6. (Java)微信之个人公众账号开发(二)——接收并处理用户消息(下)

    接下来,我们再讲一下图文消息: 如图: 大家可以先从开发者文档中了解一下图文消息的一些参数: 如上图,用户回复4时,ipastor返回了几条图文消息,上图中属于多图文消息,当然还有单图文消息,图文消息 ...

  7. 自定义ViewGroup添加布局动画

    声明几个属性值: <declare-styleable name="GridImageViewGroup"> <attr name="childVert ...

  8. android 属性动画和布局动画p165-p171

    一.属性动画 ObjectAnimator ObjectAnimator是属性动画框架中最重要的实行类,创建一个ObjectAnimator只需通过他的静态工厂类直接返回一个ObjectAnimato ...

  9. Android应用开发之所有动画使用详解

    题外话:有段时间没有更新博客了,这篇文章也是之前写了一半一直放在草稿箱,今天抽空把剩余的补上的.消失的这段时间真的好忙,节奏一下子有些适应不过来,早晨七点四十就得醒来,晚上九点四十才准备下班,好像最近 ...

随机推荐

  1. Java8 中的流式数据处理

    java8的流式处理极大了简化我们对于集合.数组等结构的操作,让我们可以以函数式的思想去操作,本篇文章将探讨java8的流式数据处理的基本使用. 一. 流式处理简介 在我接触到java8流式处理的时候 ...

  2. k8s遇到invalid type for io.k8s.api.core.v1.PodSpec.containers

    报错 error: error validating "taskcenter-v4-deployment.yaml": error validating data: Validat ...

  3. Redis安装、说明、Python中使用

    Redis安装与简单使用 Redis说明 redis是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库 redis特点 Redis 支持数据的持久化,可以将内存中的数据保存在磁盘 ...

  4. knife4j只用此插件的最简洁开发方式

    一.POM添加 在pom文件里添加包 1 <!--引入knife4j以来--> 2 <dependency> 3 <groupId>com.github.xiaoy ...

  5. Java中的异常处理机制的简单原理和应用?

    程序运行过程中可能出现各种"非预期"情况,这些非预期情况可能导致程序非正常结束. 为了提高程序的健壮性,Java提供了异常处理机制: try { s1... s2... s3... ...

  6. 如何在 Windows 和 Linux 上查找哪个线程使用的 CPU 时 间最长?

    使用 jstack 找出消耗 CPU 最多的线程代码

  7. 抽象的(abstract)方法是否可同时是静态的(static), 是否可同时是本地方法(native),是否可同时被 synchronized 修饰?

    都不能.抽象方法需要子类重写,而静态的方法是无法被重写的,因此二者是矛 盾的.本地方法是由本地代码(如 C 代码)实现的方法,而抽象方法是没有实现 的,也是矛盾的.synchronized 和方法的实 ...

  8. Python - 函数的五大参数

    Python的函数参数挺重要的,总结一下: (1)位置参数:没啥好说的,就是普通的参数. (2)默认参数: 参数形式:def power(x, n = 3): (在函数定义时通过对一个形参赋值的形式, ...

  9. Three.js 实现3D开放世界小游戏:阿狸的多元宇宙 🦊

    声明:本文涉及图文和模型素材仅用于个人学习.研究和欣赏,请勿二次修改.非法传播.转载.出版.商用.及进行其他获利行为. 背景 2545光年之外的开普勒1028星系,有一颗色彩斑斓的宜居星球 ,星际移民 ...

  10. C++“拷贝构造函数”和“等号重载”有什么区别?

    CTypeA(const CTypeB& b)CTypeA& operator=(const CTypeB& b)一直没弄懂这两个有什么区别.只知道,重载了=号,下面复制的时候 ...