乐趣区

关于openharmony:OpenHarmony标准设备应用开发二布局动画与音乐

本文作者:邢碌
上一章咱们解说了利用编译环境筹备,设施编译环境筹备,开发板烧录,将一个最简略的 OpenAtom OpenHarmony(以下简称“OpenHarmony”)程序安装到咱们的规范设施上。

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

分布式音乐播放

通过分布式音乐播放器,大家能够学到一些 ArkUI 组件和布局在 OpenHarmony 中是如何应用的,以及如何在本人的利用中实现音乐的播放,暂停等相干性能。利用成果如下图所示:

1.1 界面布局

整体布局成果如下图所示

代码参考链接:

https://gitee.com/openharmony…

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

 build() {Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceBetween}) {Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center}) {Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.End}) {Image($r("app.media.icon_liuzhuan")).width(32).height(32)
        }.padding({right: 32}).onClick(() => {this.onDistributeDevice()
        })

        Flex({direction: FlexDirection.Row, justifyContent: FlexAlign.Center}) {Image($r("app.media.Bg_classic")).width(312).height(312)
        }.margin({top: 24})

        Text(this.currentMusic.name).fontSize(20).fontColor("#e6000000").margin({top: 10})
        Text("未知音乐家").fontSize(14).fontColor("#99000000").margin({top: 10})
      }.flexGrow(1)


      Flex({direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.End}) {this.operationPannel()
        this.sliderPannel()
        this.playPannel()}.height(200)
    }
    .linearGradient({
      angle: 0,
      direction: GradientDirection.Bottom,
      colors: this.currentMusic.backgourdColor
    }).padding({top: 48, bottom: 24, left: 24, right: 24})
    .width('100%')
    .height('100%')
  }

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

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

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

 @Builder sliderPannel() {Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center}) {Text(this.currentTimeText).fontSize(12).fontColor("ff000000").width(40)
      Slider({
        value: this.currentProgress,
        min: 0,
        max: 100,
        step: 1,
        style: SliderStyle.INSET
      })
        .blockColor(Color.White)
        .trackColor(Color.Gray)
        .selectedColor(Color.Blue)
        .showSteps(true)
        .flexGrow(1)
        .margin({left: 5, right: 5})
        .onChange((value: number, mode: SliderChangeMode) => {if (mode == 2) {CommonLog.info('aaaaaaaaaaaaaa1:' + this.currentProgress)
            this.onChangeMusicProgress(value, mode)
          }
        })

      Text(this.totalTimeText).fontSize(12).fontColor("ff000000").width(40)

    }.width('100%').height(18)
  }

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

@Builder playPannel() {Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceBetween}) {Image($r("app.media.icon_music_changemode")).width(24).height(24).onClick(() => {this.onChangePlayMode()
      })
      Image($r("app.media.icon_music_left")).width(32).height(32).onClick(() => {this.onPreviousMusic()
      })
      Image(this.isPlaying ? $r("app.media.icon_music_play") : $r("app.media.icon_music_stop"))
        .width(80)
        .height(82)
        .onClick(() => {this.onPlayOrPauseMusic()
        })
      Image($r("app.media.icon_music_right")).width(32).height(32).onClick(() => {this.onNextMusic()
      })
      Image($r("app.media.icon_music_list")).width(24).height(24).onClick(() => {this.onShowMusicList()
      })
    }.width('100%').height(82)
  }

心愿通过下面这些布局的演示,能够让大家学到一些局部控件在 OpenHarmony 中的使用,这里应用的 Arkui 布局和 HarmonyOS 是统一的,目前 HarmonyOS 手机还没有公布 Arkui 的版本,大家能够在 OpenHarmony 上领先体验。罕用的布局和控件还有很多,大家能够在上面的链接中找到更多的详细信息。

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

官网参考链接:

https://gitee.com/openharmony…

1.2 播放音乐

play(seekTo) {if (this.player.state == 'playing' && this.player.src == this.getCurrentMusic().url) {return}

    if (this.player.state == 'idle' || this.player.src != this.getCurrentMusic().url) {CommonLog.info('Preload music url =' + this.getCurrentMusic().url)
      this.player.reset()
      this.player.src = this.getCurrentMusic().url
      this.player.on('dataLoad', () => {CommonLog.info('dataLoad duration=' + this.player.duration)
        this.totalTimeMs = this.player.duration
        if (seekTo > this.player.duration) {seekTo = -1}
        this.player.on('play', (err, action) => {if (err) {CommonLog.info(`MusicPlayer[PlayerModel] error returned in play() callback`)
            return
          }
          if (seekTo > 0) {this.player.seek(seekTo)
          }
        })

        this.player.play()
        this.statusChangeListener()
        this.setProgressTimer()
        this.isPlaying = true
      })
    }
    else {if (seekTo > this.player.duration) {seekTo = -1}
      this.player.on('play', (err, action) => {if (err) {CommonLog.info(`MusicPlayer[PlayerModel] error returned in play() callback`)
          return
        }
        if (seekTo > 0) {this.player.seek(seekTo)
        }
      })

      this.player.play()
      this.setProgressTimer()
      this.isPlaying = true
    }
  }

1.3 音乐暂停

 pause() {CommonLog.info("pause music")
    this.player.pause();
    this.cancelProgressTimer()
    this.isPlaying = false
  }

具体代码:

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

分布式音乐播放器我的项目下载链接:

https://gitee.com/openharmony…

接下来咱们解说如何在 OpenHarmony 中实现显示动画的成果。

显示动画

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

通过本大节,大家在上一大节的根底上,学到更多 ArkUI 组件和布局在 OpenHarmony 中的利用,以及如何在本人的利用中实现显示动画的成果。

代码链接:

https://gitee.com/openharmony…

实现步骤:

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

2.2 用变量来管制动画起始和完结的地位:用 Flex 容器包裹炸弹图片,并用 @State 装璜变量 toggle,通过变量来动静批改 Flex 的 direction 属性;布局代码如下:

@State toggle: boolean = true
private controller: CustomDialogController
@Consume deviceList: RemoteDevice[]
private confirm: () => void
private interval = null

build() {Column() {Text('游戏失败').fontSize(30).margin(20)
      Flex({
         direction: this.toggle ? FlexDirection.Column : FlexDirection.ColumnReverse,
         alignItems: ItemAlign.Center
      })
      {Image($r("app.media.bomb")).objectFit(ImageFit.Contain).height(80)
      }.height(200)

      Image($r("app.media.btn_restart")).objectFit(ImageFit.Contain).height(120).margin(10)
         .onClick(() => {this.controller.close()
               this.confirm()})
   }
   .width('80%')
   .margin(50)
   .backgroundColor(Color.White)
}

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

aboutToAppear() {this.setBombAnimate()
}

setBombAnimate() {let fun = () => {this.toggle = !this.toggle;}
   this.interval = setInterval(() => {animateTo({ duration: 1500, curve: Curve.Sharp}, fun)
   }, 1600)
}

我的项目下载链接:

https://gitee.com/openharmony…

转场动画(页面间转场)

咱们同样心愿在本大节中,能够让大家看到更多的 ArkUI 中的组件和布局在 OpenHarmony 中的应用,如何模块化的应用布局,让本人的代码更简洁易读,以及在利用中实现页面间的转场动画成果。

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

代码参考链接:

https://gitee.com/openharmony…

页面布局效果图

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

build() {Column() {Scroll() {Column() {if (this.currentPage == 1) {Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.End}) {Image($r("app.media.icon_share"))
                .objectFit(ImageFit.Cover)
                .height('60lpx')
                .width('60lpx')
            }
            .width("100%")
            .margin({top: '20lpx', right: '50lpx'})
            .onClick(() => {this.playerDialog.open()
            })

            GoodsHome({goodsItems: this.goodsItems})
          }
          else if (this.currentPage == 3) {
            // 我的
            MyInfo()}
        }
        .height('85%')
      }
      .flexGrow(1)

      HomeBottom({remoteData: this.remoteData})

    }
    .backgroundColor("white")
  }

GoodsHome() 模块对应效果图两头显示商品的局部,其次要构造为 TabContent 中蕴含的两个 List 条目所形成。具体代码如下:

@Component
struct GoodsHome {private goodsItems: GoodsData[]
  @Consume ShoppingCartsGoods :any[]
  build() {Column() {Tabs() {TabContent() {GoodsList({ goodsItems: this.goodsItems});
        }
        .tabBar("滞销榜")
        .backgroundColor(Color.White)

        TabContent() {GoodsList({ goodsItems: this.goodsItems});
        }
        .tabBar("举荐")
        .backgroundColor(Color.White)
      }
      .barWidth(500)
      .barHeight(50)
      .scrollable(true)
      .barMode(BarMode.Scrollable)
      .height('980lpx')

    }
    .alignItems(HorizontalAlign.Start)
    .width('100%')
  }
}

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

@Component
struct GoodsList {private goodsItems: GoodsData[]
  @Consume ShoppingCartsGoods :any[]
  build() {Column() {List() {
        ForEach(this.goodsItems, item => {ListItem() {GoodsListItem({ goodsItem: item})
          }
        }, item => item.id.toString())
      }
      .width('100%')
      .align(Alignment.Top)
      .margin({top: '10lpx'})
    }
  }
}

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

@Component
struct GoodsListItem {
  private goodsItem: GoodsData
  @State scale: number = 1
  @State opacity: number = 1
  @State active: boolean = false
  @Consume ShoppingCartsGoods :any[]
  build() {Column() {Navigator({ target: 'pages/DetailPage'}) {Row({ space: '40lpx'}) {Column() {Text(this.goodsItem.title)
              .fontSize('28lpx')
            Text(this.goodsItem.content)
              .fontSize('20lpx')
            Text('¥' + this.goodsItem.price)
              .fontSize('28lpx')
              .fontColor(Color.Red)
          }
          .height('160lpx')
          .width('50%')
          .margin({left: '20lpx'})
          .alignItems(HorizontalAlign.Start)

          Image(this.goodsItem.imgSrc)
            .objectFit(ImageFit.ScaleDown)
            .height('160lpx')
            .width('40%')
            .renderMode(ImageRenderMode.Original)
            .margin({right: '20lpx', left: '20lpx'})

        }
        .height('180lpx')
        .alignItems(VerticalAlign.Center)
        .backgroundColor(Color.White)
      }
      .params({goodsItem: this.goodsItem ,ShoppingCartsGoods:this.ShoppingCartsGoods})
      .margin({left: '40lpx'})
    }
  }

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

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

// 转场动画应用零碎提供的多种默认成果(平移、缩放、透明度等)
  pageTransition() {PageTransitionEnter({ duration: 1000})
      .slide(SlideEffect.Left)
    PageTransitionExit({duration: 1000})
      .slide(SlideEffect.Right)
  }
}

我的项目下载链接地址:

https://gitee.com/openharmony…

官网参考链接:

https://gitee.com/openharmony…

通过上述解说,咱们就在本人的代码中实现音乐的播放,显示动画,页面间转场动画等成果。在接下来的一章中,咱们会解说如何在 OpenHarmony 通过分布式数据管理,实现设施之间数据如何同步刷新。

在接下来的一章中,咱们将会解说分布式数据管理在 OpenHarmony 中如何实现多台设施间的数据同步更新。

退出移动版