博客 / 詳情

返回

【推薦+1】HarmonyOS官方模板優秀案例(第13期:運動健康 · 運動健身)

💡 鴻蒙生態為開發者提供海量的HarmonyOS模板/組件,助力開發效率原地起飛 💡

★ 一鍵直達生態市場組件&模板市場 , 快速應用DevEco Studio插件市場集成組件&模板 ★

★ 一鍵直達 HarmonyOS 行業解決方案 運動健康行業解決方案

👉 覆蓋20+行業,點擊查看往期案例彙總貼,持續更新,點擊收藏!一鍵三連!常看常新!

【第13期】運動健康 · 運動健身

一、概述

1.行業洞察

1)行業訴求:

運動健康類 APP 的核心及關鍵在於精準的數據採集與分析、個性化的運動/健康管理方案制定、良好的用户體驗設計以及社交激勵機制等方面。

image.png

2)行業常用三方SDK
分類 三方庫名稱 功能 支持情況
媒體 阿里雲視頻播放器SDK 音視頻 已支持
登錄認證 中國移動一鍵登錄SDK/易盾一鍵登錄SDK/創藍閃驗/極光安全認證/阿里雲號碼認證SDK/中國電信一鍵登錄SDK 登錄 已支持
分享 友盟/ShareSDK/微信分享/QQ分享/新浪微博SDK/MobTech ShareSDK 統計/推送/分享 已支持
支付 支付寶支付/微信支付/銀聯支付 支付 已支持
數據分析 友盟移動統計SD/神策數據SDK 數據收集、處理、分析、運用 已支持
性能監控 騰訊Bugly SDK/聽雲SDK/嶽鷹全景監控SDK 異常上報和運營統計 已支持
地圖 高德地圖SDK/百度地圖SDK 地圖 已支持
推送 個推/華為推送/極光PUSH/阿里推送SDK 消息推送 已支持
社交 騰訊雲 IM 即時通訊 已支持

説明:"以上三方庫及鏈接僅為示例,三方庫由三方開發者獨立提供,以其官方內容為準"

SDK鏈接:

支付寶SDK

微信支付SDK

銀聯SDK

騰訊QQ SDK

新浪微博SDK

極光PUSH SDK

友盟移動統計SDK

騰訊微信SDK

高德地圖SDK

個推

Bugly

ShareSDK

聽雲SDK

騰訊雲 IM

2.案例概覽(下載模板)

基於以上行業分析,本期將介紹鴻蒙生態市場運動健康類行業模板--運動健身應用模板,為行業提供常用功能的開發案例,模板主要分首頁、課程、計劃和我的四大模塊。

  • Stage開發模型 + 聲明式UI開發範式。
  • 分層架構設計 + 組件化拆分,支持開發者在開發時既可以選擇完整使用模板,也可以根據需求單獨選用其中的業務組件。
  • 本模板為運動健身類應用提供了常用功能的開發樣例,已集成華為賬號等服務,只需做少量配置和定製即可快速實現華為賬號的登錄、媒體播放等功能。

image.png

本模板主要頁面及核心功能如下所示:

​運動健身模板
 ├──引導頁                           
 │   ├──目標  
 │   │   ├── 性別                          
 │   │   ├── 目標                             
 │   │   └── 想鍛鍊的部位                   
 │   │         
 │   ├──身體數據        
 │   │   ├── 年齡                          
 │   │   ├── 身高                             
 │   │   └── 體重和目標體重  
 │   │                    
 │   └──關於你  
 │       ├── 是否存在傷病困擾                     
 │       └── 喜歡哪類運動、運動頻次、期望練習難度 
 │
 ├──首頁                           
 │   ├──輪播頁  
 │   │   ├── 課程封面  
 │   │   └── 課程詳情頁     
 │   │                    
 │   ├──常識普及  
 │   │   ├── 運動健身常識普及  
 │   │   └── 常識普及詳情頁 
 │   │
 │   ├──熱門課程    
 │   │   ├── 課程封面、練習難度、練習時長  
 │   │   └── 熱門課程詳情頁 
 │   │
 │   └──進階課程    
 │       ├── 課程封面、練習難度、練習時長  
 │       └── 進階課程詳情頁 
 │
 ├──課程                           
 │   ├──頂部欄  
 │   │   ├── 搜索 
 │   │   └── 課程篩選                   
 │   │         
 │   ├──熱門課程    
 │   │   ├── 課程封面、練習難度、練習時長  
 │   │   └── 熱門課程詳情頁 
 │   │
 │   ├──進階課程    
 │   │   ├── 課程封面、練習難度、練習時長  
 │   │   └── 進階課程詳情頁 
 │   │
 │   └──課程詳情頁         
 │       ├── 課程內容
 │       ├── 添加日曆
 │       ├── 課程視頻
 │       └── 會員課程                        
 │                        
 ├──計劃                           
 │   └──周計劃日期                      
 │   │         
 │   ├──計劃課程         
 │   │   ├── 課程封面、練習難度、練習時長                              
 │   │   └── 計劃課程詳情頁                            
 │   │                  
 │   ├──本週目標         
 │   │   ├── 預計減重
 │   │   ├── 目標體重
 │   │   ├── 訓練天數
 │   │   └── 消耗熱量                         
 │   │                   
 │   └──推薦課程    
 │       ├── 課程封面、練習難度、練習時長
 │       ├── 推薦課程詳情頁                                             
 │       ├── 課程內容                                  
 │       └── 添加計劃                       
 │
 └──我的                           
     ├──登錄  
     │   ├── 華為賬號一鍵登錄                          
     │   ├── 微信登錄                                                   
     │   ├── 賬密登錄
     │   └── 用户隱私協議同意                       
     │         
     ├──會員中心         
     │   ├── 會員套餐
     │   ├── 會員權益
     │   └── 會員服務協議
     │                    
     ├──個人信息         
     │   ├── 頭像、暱稱、簡介
     │   ├── 性別、年齡、身高、體重
     │   └── 目標、想鍛鍊的部位
     │
     ├──運動記錄         
     │   ├── 日運動時長、總消耗
     │   ├── 周運動時長、總消耗、累計訓練天數
     │   ├── 月運動時長、總消耗、累計訓練天數
     │   └── 年運動時長、總消耗、累計訓練天數
     │
     └──常用服務    
         ├── 我的足跡    
         ├── 我的收藏                                    
         ├── 意見反饋                   
         └── 設置
              ├── 編輯個人信息             
              ├── 隱私設置           
              ├── 通知開關  
              ├── 視頻後台播放             
              ├── 視頻默認清晰度           
              ├── 清理緩存 
              ├── 檢測版本 
              ├── 關於我們 
              └── 退出登錄 

二、應用架構設計

1.分層模塊化設計

  • 產品定製層:專注於滿足不同設備或使用場景的個性化需求,作為應用的入口,是用户直接互動的界面。

    • 本實踐支持直板機、摺疊機,為單HAP包形式,包含路由根節點、底部導航欄等。
  • 基礎特性層:用於存放相對獨立的功能UI和業務邏輯實現。

    • 本實踐的基礎特性層將應用底部導航欄的每個選項拆分成一個獨立的業務功能模塊。
    • 每個功能模塊都具備高內聚、低耦合、可定製的特點,支持產品的靈活部署。
  • 公共能力層:存放公共能力,包括公共UI組件、數據管理、外部交互和工具庫等共享功能。

    • 本實踐的公共能力層分為公共基礎能力和可分可合組件,均打包為HAR包被上層業務組件引用。
    • 公共基礎能力包含日誌、文件處理等工具類,公共類型定義,網絡庫,以及彈窗、加載等公共組件。
    • 可分可合組件將包含行業特點、可完全自閉環的能力抽出獨立的組件模塊,支持開發者在開發中單獨集成使用,詳見業務組件設計章節。

image.png

2.業務組件設計

為支持開發者單獨獲取特定場景的頁面和功能,本模板將功能完全自閉環的部分能力抽離出獨立的行業組件模塊,不依賴公共基礎能力包,開發者可以單獨集成,開箱即用,降低使用難度。

image.png

三、行業場景技術方案

1.運動記錄功能

1)場景説明
  • 通過柱狀圖的形式呈現周、月、年的運動記錄數據。

image.png

2)技術方案
  • 使用開源三方庫@ohos/mpchart呈現多類型圖表
  • 使用開源三方庫dayjs實現日期數據格式化。

2.橫屏視頻播放功能

1)場景説明
  • 用户可播放網絡視頻,視頻播放支持加解鎖、倍速等功能。

image.png

2)技術方案
  • 基於AVPlayer實現視頻播放能力。
  • 使用XComponent渲染視頻畫面。
  • ArkUI搭建控制層操作能力。

四、模板代碼

1.工程結構(下載模板)

詳細代碼結構如下所示:

ExerciseAndFitness  
├──commons
│  ├──lib_account/src/main/ets                            // 賬號登錄模塊             
│  │    ├──components
│  │    │   └──AgreePrivacyBox.ets                        // 隱私同意勾選            
│  │    ├──constants                                      // 常量                      
│  │    ├──pages  
│  │    │   ├──HuaweiLoginPage.ets                        // 華為賬號登錄頁面
│  │    │   ├──OtherLoginPage.ets                         // 其他方式登錄頁面
│  │    │   └──ProtocolWebView.ets                        // 協議H5        
│  │    ├──services                                       // 服務api            
│  │    ├──utils  
│  │    │   ├──ErrorCodeHelper.ets                        // 錯誤碼處理工具類
│  │    │   ├──HuaweiAuthUtils.ets                        // 華為認證工具類
│  │    │   ├──LoginSheetUtils.ets                        // 統一登錄半模態彈窗
│  │    │   └──WXApiUtils.ets                             // 微信登錄事件處理類       
│  │    └──viewmodels                                     // 視圖模型
│  │
│  ├──lib_api/src/main/ets                              // 服務端api模塊  
│  │    ├──database                                       // 數據庫 
│  │    ├──params                                         // 請求響應參數 
│  │    └──services                                       // 服務api  
│  │
│  ├──lib_common/src/main/ets                             // 基礎模塊             
│  │    ├──components                                     // 通用組件             
│  │    ├──constants                                      // 通用常量
│  │    ├──dialogs                                        // 通用彈窗 
│  │    ├──mocks                                          // 模擬數據
│  │    ├──models                                         // 狀態觀測模型 
│  │    ├──types                                          // 類型
│  │    └──utils                                          // 通用方法                       
│  │ 
│  └──lib_widget/src/main/ets                             // 通用UI模塊             
│       └──components
│           └──NavHeaderBar.ets                           // 自定義標題欄
│
├──components
│  ├──aggregated_payment                                  // 通用支付組件
│  ├──module_chart                                        // 圖表組件 
│  ├──module_feedback                                     // 意見反饋組件 
│  ├──module_imagepreview                                 // 圖片預覽組件 
│  ├──module_player                                       // 播放組件 
│  ├──module_search                                       // 搜索組件
│  └──module_transition                                   // 動畫組件         
│      
├──features
│  ├──home/src/main/ets                                   // 首頁模塊                   
│  │    ├──pages
│  │    │   ├──CommonKnowledgeActivatePage.ets            // 激活頁
│  │    │   ├──CommonKnowledgeDrawPage.ets                // 拉伸頁
│  │    │   ├──CommonKnowledgeEquipPage.ets               // 裝備頁
│  │    │   ├──CommonKnowledgePage.ets                    // 常識頁面
│  │    │   ├──CommonKnowledgeStrainPage.ets              // 避免受傷頁
│  │    │   ├──CommonKnowledgeWarmPage.ets                // 熱身頁
│  │    │   ├──CommonKnowledgeYogaPage.ets                // 瑜伽頁
│  │    │   └──HomePage.ets                               // 首頁頁面
│  │    └──viewmodels  
│  │        └──CommonKnowledgePageVM.ets                  // 常識頁面視圖模塊
│  ├──course/src/main/ets                                 // 課程模塊    
│  │    ├──pages
│  │    │   ├──AdvancedCoursePage.ets                     // 進階課程頁面
│  │    │   ├──CourseDetailPage.ets                       // 課程詳情頁面
│  │    │   ├──CoursePage.ets                             // 課程頁面 
│  │    │   ├──CoursePlayer.ets                           // 課程視頻
│  │    │   ├──CourseSearch.ets                           // 課程搜索
│  │    │   ├──FilterPage.ets                             // 課程篩選
│  │    │   └──HotCoursePage.ets                          // 熱門課程 
│  │    └──viewmodels 
│  │        ├──AddDateDialog.ets                          // 添加日程
│  │        ├──AdvancedCoursePageVM.ets                   // 進階課程視圖模型
│  │        ├──Calendar.ets                               // 日曆
│  │        ├──CoursePageVM.ets                           // 課程視圖模型
│  │        ├──CustomDialog.ets                           // 自定義彈窗
│  │        └──HotCoursePageVM.ets                        // 熱門課程視圖模型                  
│  │
│  ├──mine/src/main/ets                                   // 我的模塊             
│  │    ├──components
│  │    │   ├──CourseItemComponent.ets                    // 課程組件
│  │    │   ├──LeftSwipeComponent.ets                     // 左滑組件
│  │    │   ├──VipBenefits.ets                            // VIP權益
│  │    │   ├──VipOpen.ets                                // 開通VIP
│  │    │   ├──VipOperation.ets                           // VIP操作
│  │    │   └──VipPackage.ets                             // VIP套餐包             
│  │    ├──constants                                      // 常量        
│  │    ├──model                                          // 模型        
│  │    ├──preview                                        // 預覽          
│  │    ├──types                                          // 類型        
│  │    ├──utils                                          // 工具類        
│  │    ├──viewmodels                                     // 視圖模型
│  │    └──pages 
│  │        ├──HistoryPage.ets                            // 我的足跡
│  │        ├──MarkPage.ets                               // 我的收藏
│  │        ├──RecordPage.ets                             // 運動記錄
│  │        ├──VIPPage.ets                                // 會員頁面
│  │        └──MinePage.ets                               // 我的頁面              
│  │
│  ├──plan/src/main/ets                                   // 計劃模塊                  
│  │    ├──pages
│  │    │   ├──CoursePlanPage.ets                         // 課程計劃詳情頁面
│  │    │   ├──PlanPage.ets                               // 計劃主頁
│  │    │   └──RecommendationCoursePage.ets               // 推薦課程頁面       
│  │    └──viewmodels                                     
│  │        └──PlanPageVM.ets                             // 計劃視圖模塊
│  │
│  └──setting/src/main/ets                                // 設置模塊             
│       ├──components
│       │   ├──SettingCard.ets                            // 設置卡片
│       │   └──SettingSelectDialog.ets                    // 設置選項彈窗               
│       │──pages
│       │   ├──SettingAbout.ets                           // 關於頁面
│       │   ├──SettingH5.ets                              // H5頁面
│       │   ├──SettingNetwork.ets                         // 視頻播放設置頁面
│       │   ├──SettingPage.ets                            // 設置頁面
│       │   ├──SettingPersonal.ets                        // 編輯個人信息頁面
│       │   └──SettingPrivacy.ets                         // 隱私設置頁面        
│       ├──types                                          // 類型          
│       └──viewmodels                                     // 視圖模型
│
└──products
   └──phone/src/main/ets                                  // phone模塊
        ├──common                        
        │   ├──AppTheme.ets                               // 應用主題色
        │   ├──AppUtils.ets                               // 應用設置工具類
        │   ├──Constants.ets                              // 業務常量
        │   ├──NetworkUtils.ets                           // 網絡工具類
        │   ├──Types.ets                                  // 數據模型
        │   ├──WantUtils.ets                              // want工具類
        │   └──WindowUtils.ets                            // 窗口工具類
        ├──components                    
        │   └──CustomTabBar.ets                           // 應用底部Tab
        │──pages   
        │   ├──AgreeDialogPage.ets                        // 隱私同意彈窗
        │   ├──GuidePage_*.ets                            // 引導頁面
        │   ├──Index.ets                                  // 入口頁面
        │   ├──IndexPage.ets                              // 應用主頁面
        │   ├──PrivacyPage.ets                            // 查看隱私協議頁面
        │   ├──SafePage.ets                               // 隱私同意頁面
        │   └──SplashPage.ets                             // 開屏廣告頁面      
        └──viewmodels                                     // 視圖模型

2.關鍵代碼解讀

本篇代碼非應用的全量代碼,只包括應用的部分能力的關鍵代碼。

1)圖表組件
​@Builder
markerBuilder() {
  // 是否在圖表content內&&是否有數據
  if (this.customUiInfo.isInbounds && this.customUiInfo.data && this.customUiInfo.y) {
    Column() {
      Text() {
        Span(`${this.customUiInfo.data.getY()}分鐘`);
      }
      .fontSize($r('sys.float.Body_M'));
    }
    .borderRadius(99)
    .justifyContent(FlexAlign.Center)
    .padding(12)
    .backgroundColor(Color.White)
    .shadow({
      radius: 20,
      offsetX: 0,
      offsetY: 0,
      color: '#33000000',
    })
    .width(this.customUiInfo.width)
    .height(this.customUiInfo.height)
    .margin({ left: this.customUiInfo.x, top: this.customUiInfo.y })
    .onAppear(() => {
      const timer = setTimeout(() => {
        this.customUiInfo.showUi = false;
        clearTimeout(timer);
      }, 2000);
    })
    .alignItems(HorizontalAlign.Start)
    .onClick(() => {
      this.customUiInfo.showUi = false;
    });
  }
}

async initChartSetting() {
  // 顯示描述
  this.model.getDescription()?.setEnabled(false);
  // 初始化動畫時長
  this.model.animateY(1000);
  // 顯示圖例
  this.model.getLegend()?.setEnabled(false);
  // 設置額外偏移量
  this.model.setExtraOffsets(10, 10, 10, 5);
  // 繪製柱狀體陰影背景
  this.model.setDrawBarShadow(false);
  // 柱狀體上方顯示數值
  this.model.setDrawValueAboveBar(false);
  // 為圖表添加數據選擇的監聽器
  this.model.setOnChartValueSelectedListener(this._valueSelectedListener);
  // 繪製圖表背景色
  this.model.setDrawGridBackground(false);
  // 設置左軸
  const leftAxis = this.model.getAxisLeft();
  if (leftAxis) {
    leftAxis.setAxisMinimum(0);
    leftAxis.setGridColor(ChartColor.argb(60, 0, 0, 0));
    leftAxis.setTextColor(ChartColor.argb(200, 0, 0, 0));
    leftAxis.setAxisLineColor(ChartColor.rgb(255, 255, 255));
    leftAxis.setLabelXOffset(-10);
  }
  // 設置右軸不顯示
  this.model.getAxisRight()?.setEnabled(false);
  const xAxis = this.model.getXAxis();
  if (xAxis) {
    xAxis.setValueFormatter(new MyAxisValueFormatter(this.chartData.month));
    xAxis.setPosition(XAxisPosition.BOTTOM);
    xAxis.setDrawGridLines(false);
    xAxis.setAxisLineColor(ChartColor.argb(60, 0, 0, 0));
    xAxis.setTextColor(ChartColor.argb(200, 0, 0, 0));
  }
  // 初始化圖表數據
  this.getChartData();
}

async getChartData() {
  const month = new Date(this.chartData.month);
  this.model.getXAxis()?.setValueFormatter(new MyAxisValueFormatter(this.chartData.month));
  const totalDayNum = new Date(month.getFullYear(), month.getMonth() + 1, 0).getDate();
  this.displayData = [];
  for (let i = 1; i <= totalDayNum; i++) {
    const bill = this.chartData.data.find((item) => {
      const day = item.date.split('-')[2];
      return Number(day) === i;
    });
    if (bill) {
      this.displayData.push({
        date: bill.date,
        value: bill.value,
      });
    } else {
      const date = dayjs().set('month', month.getMonth()).set('date', i);
      this.displayData.push({
        date: date.format('YYYY-MM-DD'),
        value: 0,
      });
    }
  }
  await this.setData();
}

async setData() {
  let dataSetList: JArrayList<IBarDataSet> = new JArrayList<IBarDataSet>();
  let values: JArrayList<BarEntry> = new JArrayList<BarEntry>();
  for (let i = 0; i < this.displayData.length; i++) {
    values.add(new BarEntry(i + 1, this.displayData[i].value));
  }

  let dataSet: BarDataSet = new BarDataSet(values, 'DataSet');
  dataSet.setColorByColor(this.initColor);
  dataSet.setDrawValues(false);
  dataSet.setHighLightColor(this.highlightColor);
  // 顯示數據格式化
  dataSetList.add(dataSet);

  let barData: BarData = new BarData(dataSetList);
  barData.setBarWidth(0.85);
  if (this.model) {
    this.model.setData(barData);
  }
  return barData;
}
1)視頻播放組件
// 設置窗口方向
setR(orientation: number) {
  window.getLastWindow(getContext(this)).then((win) => {
    win.setPreferredOrientation(orientation).then(() => {
    }).catch(() => {
    })
  }).catch(() => {
  })
}

// 設置沉浸式窗口
setFullScreen(isLayoutFullScreen: boolean) {
  window.getLastWindow(getContext(this)).then((win: window.Window) => {
    win.setWindowLayoutFullScreen(isLayoutFullScreen).then(() => {
    }).catch(() => {
    })
  }).catch(() => {
  })
  this.fullScreen(isLayoutFullScreen)
  this.setComponentHeight()
}

regDisplayListener(): void {
  display.on('foldStatusChange', async (curFoldStatus: display.FoldStatus) => {
    // 同一個狀態重複觸發不做處理
    if (this.curFoldStatus === curFoldStatus) {
      return;
    }
    this.curFoldStatus = curFoldStatus;
    this.setComponentHeight()
  })
}

setComponentHeight() {
  let screenWidth = display.getDefaultDisplaySync().width
  if (this.curFoldStatus === display.FoldStatus.FOLD_STATUS_FOLDED ||
    this.curFoldStatus === display.FoldStatus.FOLD_STATUS_UNKNOWN) {
    this.componentHeight = '100%'
  } else {
    if (this.isLayoutFullScreen) {
      let height = (this.getUIContext().px2vp(screenWidth) - 32) * 9 / 16
      this.componentHeight = height.toString() + 'vp'
    } else {
      this.componentHeight = '100%'
    }
  }
}

async aboutToAppear() {
  if (this.movieItems && this.movieItems.length > 0) {
    this.playerVM.movieItemList = this.movieItems
    this.playerVM.movieItem = this.playerVM.movieItemList[this.playerIndex]
  }
  PipManager.getInstance().init(getContext(this), this.playerVM.navId)
  window.getLastWindow(getContext(this)).then((currentWindow: window.Window) => {
    this.mWindow = currentWindow;
    // 獲取窗口屬性
    let properties = currentWindow.getWindowProperties();
    let rect = properties.windowRect;
    if (this.getUIContext().px2vp(rect.height) <= 680) {
      this.windowStatusType = 5
      this.playerVM.windowStatusType = this.windowStatusType
      this.isLayoutFullScreen = false
      this.setR(1)
      this.setFullScreen(false)
    }
    currentWindow.on('windowStatusChange', (windowStatusType) => {
      this.windowStatusType = windowStatusType
      this.playerVM.windowStatusType = this.windowStatusType
      if (windowStatusType === 5) {
        this.isLayoutFullScreen = false
        this.setR(1)
        this.setFullScreen(false)
      }
    });
  })
  this.isLayoutFullScreen = true
  this.setR(this.isLayoutFullScreen ? 2 : 1)
  this.setFullScreen(this.isLayoutFullScreen)
  emitter.on('playerPause', (event: emitter.EventData) => {
    let isPlaying = event.data!.isPlaying as boolean
    if (isPlaying) {
      PipManager.getInstance().player.isResetPause = false
      PipManager.getInstance().player.isPlaying = true
    } else {
      PipManager.getInstance().player.isResetPause = true
      PipManager.getInstance().player.isPlaying = false
    }
  })
  emitter.on('autoStartPip', () => {
    if (this.playerVM.autoStartEnabled) {
      if (PipManager.getInstance().player.isPipOpen) {
      } else {
        PipManager.getInstance().startPip()
        PipManager.getInstance().updatePiPControlStatus();
      }
    } else {
      if (PipManager.getInstance().player.isPipOpen) {
      } else {
        PipManager.getInstance().player.isPlaying = false
      }
    }
  })
  emitter.on('chapterDetailBack', () => {
    if (!PipManager.getInstance().player.isPipOpen) {
      // 釋放AVPlayer資源
      PipManager.getInstance().stopPip()
      PipManager.getInstance().player.isCreate = true
      PipManager.getInstance().player.release();
    }
  })
  if (display.isFoldable()) {
    this.regDisplayListener();
  }
  this.curFoldStatus = display.getFoldStatus()
  this.setComponentHeight()
}

aboutToDisappear() {
  // 釋放AVPlayer資源
  PipManager.getInstance().player.isCreate = true
  PipManager.getInstance().player.release();
  this.setR(1)
  this.setFullScreen(true)
  this.isLayoutFullScreen = false
}

@Builder
xComponentView() {
  Column() {
    XComponent({
      type: XComponentType.SURFACE,
      controller: PipManager.getInstance().getXComponentController()
    })
      .id('XComponent01')
      .layoutWeight(1)
      .onLoad(() => {
        this.surfaceId = PipManager.getInstance().getXComponentController().getXComponentSurfaceId();
        // 將surfaceId設置給媒體源
        PipManager.getInstance().getXComponentController().onSurfaceCreated(this.surfaceId)
        PipManager.getInstance().player.init(this.courseId, this.playerVM.movieItem.movieUrl,
          this.playerVM.movieItem.learnProgress)
        PipManager.getInstance().player.callbackTimeUpdate = (vol: number, total: number) => {
          this.callbackTimeUpdate(vol, total)
          this.playerVM.movieItem.learnProgress = Math.floor(vol / total * 100)
        }
      })
  }
  .width('100%')
  .height(this.componentHeight)
}

以上代碼展示了運動健身應用的核心功能實現,包括運動記錄柱狀圖、視頻播放等技術方案。

3.模板集成

本模板提供了兩種代碼集成方式,供開發者自由使用。

1)整體集成(下載模板)

開發者可以選擇直接基於模板工程開發自己的應用工程。

  • 模板代碼獲取:

    • 通過IDE插件創建模板工程,開發指導。
    • 通過生態市場下載源碼, 下載模板。
    • 通過開源倉訪問源碼,倉庫地址。
  • 打開模板工程,根據README説明中的快速入門章節,將自己的應用信息配置在模板工程內,即可運行並查看模板效果。

image.png

    • 對接開發者自己的服務器接口,轉換數據結構,展示真實的雲側數據。

在commons/lib_api/src/main/ets/params/response/AuthorResponse.ets文件中將雲側開發者自定義的數據結構轉換為端側數據結構。

image.png

2)按需集成

若開發者已搭建好自己的應用工程,但暫未實現其中的部分場景能力,可以選擇取用其中的業務組件,集成在自己的工程中。

  • 組件代碼獲取:

    • 通過IDE插件下載組件源碼。開發指導
    • 通過生態市場下載組件源碼。 下載地址
  • 下載組件源碼,根據README中的説明,將組件包配置在自己的工程中。
  • 根據API參考和示例代碼,將組件集成在自己的對應場景中。

以上是第13期"運動健身"行業優秀案例的內容,更多行業敬請期待~

歡迎下載使用行業模板"點擊下載",若您有體驗和開發問題,或者迫不及待想了解XX行業的優秀案例,歡迎在評論區留言,小編會快馬加鞭為您解答~

同時誠邀您添加下方二維碼加入"組件模板活動社羣",精彩上新&活動不錯過!

image.png

👉 HarmonyOS官方模板優秀案例系列持續更新, 點擊查看往期案例彙總貼, 點擊收藏“💗”方便查找!

👉【集成有禮】HarmonyOS官方模板集成創新活動,揮灑創意,贏精美大禮!點擊參加

👉【HarmonyOS行業解決方案】為各行業鴻蒙應用提供全流程技術方案。點擊查看

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.