OpenHarmony标准设备应用开发(二)——布局、动画与音乐

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

一、分布式音乐播放

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

1.1 界面布局

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

首先是页面整体布局,部分控件是以模块的方式放在整体布局中的,如 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 开发的面向多种全场景智能设备的商用版本。是结合其自有特性和能力开发的新一代智能终端操作系统。

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
  }

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

二、显示动画

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

通过本小节,大家在上一小节的基础上,学到更多 ArkUI 组件和布局在 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)
}

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

我们同样希望在本小节中,可以让大家看到更多的 ArkUI 中的组件和布局在 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 条目所构成。具体代码如下:

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")
  }

上面代码中的 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)
  }
}

为了帮助到大家能够更有效的学习OpenHarmony 开发的内容,下面特别准备了一些相关的参考学习资料:

OpenHarmony 开发环境搭建:https://qr18.cn/CgxrRy

《OpenHarmony源码解析》:https://qr18.cn/CgxrRy

  • 搭建开发环境
  • Windows 开发环境的搭建
  • Ubuntu 开发环境搭建
  • Linux 与 Windows 之间的文件共享
  • ……

系统架构分析:https://qr18.cn/CgxrRy

  • 构建子系统
  • 启动流程
  • 子系统
  • 分布式任务调度子系统
  • 分布式通信子系统
  • 驱动子系统
  • ……

OpenHarmony 设备开发学习手册:https://qr18.cn/CgxrRy

在这里插入图片描述

OpenHarmony面试题(内含参考答案):https://qr18.cn/CgxrRy

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/632794.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

.NET 分享一款Web打包和解压缩工具

01本文概要 在.NET部署环境中,利用IIS中间件开启对ASP的支持,可以实现许多强大的文件操作功能。特别是在一些需要进行预编译的情况下,通过上传ASP脚本,可以获得WebShell,从而方便地进行各种操作。本文将介绍一个名为S…

一文搞懂车载系统开发学习路线

前言 随着汽车技术的快速发展和智能化趋势的加强,车载信息娱乐系统已经成为现代汽车不可或缺的一部分。因此,车载软件市场正在迅速增长,这为Android应用开发提供了新的机会。恰好近年来大环境不是很理想,车载开发不失为Android应…

概率论统计——大数定律

大数定律 弱大数定律(辛钦大数定律) 利用切比雪夫不等式,证明弱大数定律 应用 伯努利大数定理,(辛钦大数定理的推论) 证明伯努利大数定理 注意:这里将二项分布转化成0,1分布来表示,…

电能表抄表软件是什么?

1.电能表抄表软件简述 电能表抄表软件是当代电力系统中不可或缺的一部分,它通过大数据技术性完成了远程控制抄表、数据库管理及其电费测算等服务,大大提高了工作效能并降低了人为失误。这类软件的诞生,促使供电公司可以实时监控系统与分析电…

【Uniapp】图片修复对比组件

效果图 不废话&#xff0c;直接上源码&#xff01; 组件直接用 <template><viewclass"img-comparison-container":style"width: width rpx;height: height rpx"><view class"before-image" :style"width: x rpx&quo…

【MATLAB】fminsearchbnd()函数安装包下载

fminsearchbnd()函数 链接&#xff1a;https://pan.baidu.com/s/1apc6_f92rDnV_NwHpZZpDQ?pwdxul8 提取码&#xff1a;xul8 fminsearchbnd, fminsearchcon - File Exchange - MATLAB Central (mathworks.cn) 若链接失效&#xff0c;可以自行注册下载&#xff0c;操作也很简…

一键解锁!贸易行业实现银行与财务系统秒级对接,效率飙升!

客户介绍 某贸易有限公司是一家实力雄厚的工贸一体跨国集团企业。作为行业内的佼佼者&#xff0c;该公司以出口家纺产品和生产销售建材洁具为核心业务。公司始终坚持以市场为导向&#xff0c;不断创新和优化产品和服务&#xff0c;以满足不断变化的市场需求。 客户痛点 以往&…

文本三剑客-awk

一、awk的介绍 1.1awk的简介 AWK 是一种处理文本文件的语言&#xff0c;是一个强大的文本分析工具 可以在无交互的模式下实现复杂的文本操作 相较于sed常作用于一整个行的处理&#xff0c;awk则比较倾向于一行当中分成数个字段来处理&#xff0c;因为awk相当适合小型的文本…

Winform自定义控件 —— 开关

在开始阅读本文之前&#xff0c;如果您有学习创建自定义控件库并在其他项目中引用的需求&#xff0c;请参考&#xff1a;在Visual Studio中创建自定义Winform控件库并在其他解决方案中引用https://blog.csdn.net/YMGogre/article/details/126508042 0、引言 由于 Winform 框架并…

C++ 程序员常用的VScode的插件

vscode中好用的插件 Better CommentsBookmarksC/C ThemeChinese (Simplified) (简体中文) Language Pack for Visual Studio CodeclangdClang-FormatCodeLLDBCMakeCMake ToolsCode RunnerCode Spell CheckerCodeSnapColor Highlightvscode-mindmapDraw.io IntegrationError Len…

推荐一款实用的便捷工具:windows输入法删除工具

这是一款输入法删除的工具&#xff0c;能够辅助个人来彻底的删除你电脑上面的输入法&#xff0c;以极为完整的方式来进行卸载&#xff0c;在你找不到卸载的方式之时这款软件极为的适用&#xff0c;能够帮助你面对这个场景&#xff0c;满足个人对于卸载上面的需求! 目录 一、下…

低功耗音频编解码器CJC8990

由工采网代理的CJC8990是一款低功耗音频编解码器&#xff0c;拥有先进的功能并提供高质量音频&#xff0c;非常适合于便携式数字音频应用&#xff0c;支持多种音频数据格式&#xff0c;包括I2S, DSP模式。 产品介绍&#xff1a; 该芯片工作电压&#xff1a;1.5V&#xff5e;3…

【EasyExcel】EasyExcel合并指定列单元格导出详解设置导出样式

【EasyExcel】EasyExcel合并指定列单元格导出&设置导出样式 需求分析 需求背景 许多报表需要对相同数据的单元格进行合并&#xff0c;以提高数据的可读性和美观性。例如&#xff0c;在销售报表中&#xff0c;将相同客户的订单合并在一起。同时&#xff0c;报表中的标题和内…

MySQL中order by排序时,数据存在null,排序在最前面

order by排序是最常用的功能&#xff0c;但是排序有时会遇到数据为空null的情况&#xff0c;这样排序就会乱了&#xff0c;这里以MySQL为例&#xff0c;记录我遇到的问题和解决思路。 sql 排序为 null 值问题&#xff1a; 排序时我们用 receive_date(一个统计的时间&#xff…

物业水电抄表系统的全面解析

1.系统概述 物业水电抄表系统是现代物业管理中的重要组成部分&#xff0c;它通过自动化的方式&#xff0c;实时监控和记录居民或企业的水电使用情况&#xff0c;极大地提高了工作效率&#xff0c;降低了人工抄表的错误率。该系统通常包括数据采集、数据传输、数据分析和数据展…

python创建新环境并安装pytorch

python创建新环境并安装pytorch 一、创建新环境1、准备工作2、创建虚拟环境并命名3、激活虚拟环境 二、安装pytorch1、pytorch官网2、选择与你的系统相对应的版本3、安装成功 一、创建新环境 1、准备工作 本次创建的环境是在anaconda环境下&#xff0c;否则需要在纯净环境下创…

centOS忘记密码的处理办法

1、开机后在出现内核选项时&#xff0c;按 e&#xff1b; 2、在Linux 开头的这行&#xff0c;输入 rd.break 如下图&#xff1b; 3、然后&#xff0c;执行&#xff1a;CtrlX&#xff1b; 4、进入之后是 switch_root:/#输入 mount -o rw,remount /sysroot 以读写方式重新挂载 /s…

初讲树,二叉数(搜索二叉树,实现的方法<链式,顺序>)

目录 1.树的概念及其结构 1.1树的概念 1.2树相关的概念 1.3树的表示 2.二叉树概念及其结构 2.1概念 2.2现实中的二叉树 2.3特殊的二叉树 2.4二叉树的性质 2.5二叉树存储结构 2.5.1链式存储 2.5.2顺序存储 3.搜索二叉树 1.树的概念及其结构 1.1树的概念 树是一种非…

从零入门激光SLAM(十六)——卡尔曼滤波基础

一、卡尔曼滤波简介KF 卡尔曼滤波器&#xff08;Kalman Filter&#xff09;是一种用于估计动态系统状态的递归算法。它通过结合系统的动态模型和噪声观测数据&#xff0c;提供对系统状态的最优估计。卡尔曼滤波器广泛应用于信号处理、控制系统、导航、计算机视觉等领域。 卡尔…

无人机超强教程!无人机图像拼接、航拍植被动态定量化研究、激光雷达地形测量与河网水系提取

查看原文>>>无人机生态环境监测、图像处理与GIS数据分析综合实践技术应用 目录 一、无人机航拍基本流程、航线规划与飞行实践 二、无人机图像拼接软件的学习与操作实践 三、无人机图像拼接典型案例详解 四、无人机图像拼接数据在GIS中的处理与分析 五、无人机图…