OpenHarmony標準設備應用開發(二)——佈局、動畫與音樂

来源:https://www.cnblogs.com/openharmony/archive/2022/04/07/16113326.html
-Advertisement-
Play Games

我們通過知識體系新開發的幾個基於 OpenHarmony3.1 Beta 標準系統的樣例:分散式音樂播放、傳炸彈、購物車等樣例,分別介紹下音樂播放、顯示動畫、動畫轉場(頁面間轉場)三個進階技能。 ...


(以下內容來自開發者分享,不代表 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 以及剛纔所說的三個模塊所構成。

 

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/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components.md


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-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 屬性;佈局代碼如下:

 

@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-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() 構成,該三個模塊我們會分別說明。具體代碼如下:

 

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-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 通過分散式數據管理,實現設備之間數據如何同步刷新。

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 通常,PDF格式的文檔能支持的編輯功能不如office文檔多,針對PDF文檔裡面有表格數據的,如果想要編輯表格裡面的數據,可以將該PDF文檔轉為Excel格式,然後編輯。本文,將以C#代碼為例,介紹如何實現由PDF格式到Excel文檔格式的轉換。下麵是具體步驟。 【dll引用方法】 方法1 在程式中 ...
  • 一、原子操作 先看一段問題代碼 /// <summary> /// 獲取自增 /// </summary> public static void GetIncrement() { long result = 0; Console.WriteLine("開始計算"); //10個併發執行 Parall ...
  • 大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家分享的是i.MXRT1170下單獨線上調試從核工程的方法(基於IAR)。 兩年前痞子衡寫過一篇《雙核i.MXRT1170之Cortex-M7與Cortex-M4互相激活之道》,那篇文章從離線啟動的角度介紹了跑雙核應用的基本方法,基本上把雙核啟動 ...
  • 一、調用系統的IsDebuggerPresent函數 (1)實現程式 最簡單也是最基礎的,Windows提供的API介面:IsDebuggerPresent(),這API實際上就是訪問PEB的BeingDebugged標誌來判斷是否處於調試狀態。 使用vs調試此段代碼,彈出"檢測到調試器"。 #in ...
  • 鏡像下載、功能變數名稱解析、時間同步請點擊 阿裡雲開源鏡像站 OneBlog是什麼? OneBlog,一個簡潔美觀、功能強大並且自適應的Java博客。使用springboot開發,前端使用Bootstrap。支持移動端自適應,配有完備的前臺和後臺管理功能。 簡單瞭解了OneBlog後,下麵就跟隨博主一起看下 ...
  • 1.併發事務問題 1)臟讀:一個事物讀到另一個事務還沒有提交的數據。 2)不可重覆讀:一個事務先後讀取同一條記錄,但兩次讀取的數據不同,稱之為不可重覆讀。 3)幻讀:一個事務按照條件查詢數據時,沒有對應的數據行,但是在插入數據時,又發現這行數據已經存在,好像出現了“幻影”。 2.事務隔離級別 隔離級 ...
  • 1. LOAD DATA INFILE 為什麼比 INSERT 快? 2. sysbench 壓測 MySQL 的四個標準步驟。 3. 怎麼讓 sysbench 支持 LOAD DATA LOCAL INFILE 命令,讓導數速度提升 30%? ...
  • 為了更好的理解,我們使用 eTS 開發了一款如下動圖所示的井字過三關游戲來講解分散式數據管理在應用中的使用。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...