写点什么

【案例 +1】HarmonyOS 官方模板优秀案例 (第 10 期:教育行业·课堂应用)

  • 2025-10-28
    北京
  • 本文字数:15931 字

    阅读完需:约 52 分钟

大小:1.19M时长:06:55
【案例+1】HarmonyOS官方模板优秀案例  (第10期:教育行业·课堂应用)

🚀🚀🚀🚀

鸿蒙生态为开发者提供海量的 HarmonyOS 模板/组件,助力开发效率原地起飞

★一键直达生态市场组件&模板市场 , 快速应用DevEco Studio插件市场集成组件&模板 ★

在之前第三期为大家介绍了“教育备考案例”(^_^点这里立即回顾

本期带来新上模板“课堂应用模板”的案例解析

👉覆盖 20+行业,点击查看往期案例汇总贴,持续更新,点击收藏!一键三连!常看常新!


【第 10 期】教育行业 ·课堂应用

一、 概述

1. 行业洞察

1) 行业诉求:

  • 精准分发:面对不同的受众教育类应用有不同的业务场景,产出适配内容、精准题库等,并以高效且契合场景的方式进行分发,最终实现优质教育资源的有效传递。

    高效流畅、操作敏捷是教育类应用不同场景重要诉求,在线学习、考试等场景出现卡顿会严重影响学习、考试的。

    需具备智能刷题与精准辅导能力:基于大数据和算法,依据答题情况判断用户知识掌握状况,动态调整出题难度,推送契合的学习内容。

    多端协同能力:实现手机、平板、PC 端数据实时互通,提供离线功能,便于用户利用碎片化时间用于刷题或知识点复习,并可在线后同步学习进度。


2) 行业常用三方 SDK


说明:“以上三方库及链接仅为示例,三方库由三方开发者独立提供,以其官方内容为准”


腾讯浏览服务SDK     高德地图定位   百度地图SDK    极光Push SDK    火山引擎SDK    同盾SDK    友盟SDK    微信支付SDK    支付宝SDK    听云SDK    福昕 PDF SDK    网易云信 IM SDK    保利威视频直播webSDK    支付宝分享SDK       

2. 案例概览(下载模板

基于以上行业分析,本期将介绍鸿蒙生态市场教育类行业模板——课堂应用模板,为行业提供常用功能的开发案例,模板主要分首页、学习、我的三大模块。

  • Stage 开发模型 + 声明式 UI 开发范式。

  • 分层架构设计+ 组件化拆分,支持开发者在开发时既可以选择完整使用模板,也可以根据需求单独选用其中的业务组件。

  • 本模板已集成华为账号、广告等服务,只需做少量配置和定制即可快速实现华为账号的登录、媒体播放等功能。

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

教育学习应用模板  ├──首页                             │   ├──顶部栏-搜索    │   │   ├── 搜索                            │   │   └── 职级分类选择                        │   │           │   ├──课堂列表      │   │   ├── 动态布局                                               │   │   ├── 信息流                           │   │   └── 功能区                        │   └──课堂详情      │       ├── 图文                                               │       ├── 收藏、评论                           │       ├── 分享(微信、朋友圈、QQ、生成海报、复制链接等)  │       └── 视频                        ├──学习                             │   ├──顶部栏                          │   │   └── 搜索                        │   ├──课堂列表      │   └──视频详情页           │       ├── 竖屏播放  │       ├── 横屏播放  │       ├── 暂停、播放、进度调节、倍速、选集、画中画  │       └── 收藏、评论、分享                              └──我的                                 ├──登录        │   ├── 华为账号一键登录                                │   ├── 微信登录                                                         │   ├── 账密登录      │   └── 用户隐私协议同意                             ├──个人主页               │   └── 头像、昵称、简介      ├──功能栏          │   ├── 我的课程                                              │   ├── 我的收藏                         │   ├── 我的下载                                   │   └── 我的错题      └──常用服务              ├── 订单                                                  ├── 消息                  ├── 评论              ├── 观看记录                     ├── 意见反馈                               └── 设置               ├── 编辑个人信息                            ├── 隐私设置                          ├── 播放设置                            ├── 清理缓存                          ├── 检测版本                ├── 关于我们                └── 退出登录   
复制代码

  二、 应用架构设计

1. 分层化模块设计
  • 产品定制层:专注于满足不同设备或使用场景的个性化需求,作为应用的入口,是用户直接互动的界面。

o 本实践支持直板机、折叠机,为单 HAP 包形式,包含路由根节点、底部导航栏等。

  • 基础特性层:用于存放相对独立的功能 UI 和业务逻辑实现。

o 本实践的基础特性层将应用底部导航栏的每个选项拆分成一个独立的业务功能模块。

o 每个功能模块都具备高内聚、低耦合、可定制的特点,支持产品的灵活部署。

  • 公共能力层:存放公共能力,包括公共 UI 组件、数据管理、外部交互和工具库等共享功能。

o 本实践的公共能力层分为公共基础能力和可分可合组件,均打包为 HAR 包被上层业务组件引用。

o 公共基础能力包含日志、文件处理等工具类,公共类型定义,网络库,以及弹窗、加载等公共组件。

o 可分可合组件将包含行业特点、可完全自闭环的能力抽出独立的组件模块,支持开发者在开发中单独集成使用,详见业务组件设计章节。


本模板详细工程结构可见工程结构章节。

2. 业务组件设计

为支持开发者单独获取特定场景的页面和功能,本模板将功能完全自闭环的部分能力抽离出独立的行业组件模块,不依赖公共基础能力包,开发者可以单独集成,开箱即用,降低使用难度。


三、 行业场景技术方案

1. 视频播放控制层定制化

1)场景说明

用户可播放网络视频,视频播放支持加解锁、画中画、倍速、等功能。


 

2)技术方案

· 基于AVPlayer实现视频播放能力。

· 使用XComponent渲染视频画面。

· ArkUI 搭建控制层操作能力。

2. 画中画

1)场景说明

用户可启动画中画功能同时操作其他界面不影响视频观看。


 

2)技术方案

· 采用XComponent实现画中画能力。

· 封装 PipManager 工具类封装画中画相关 API。

四、 模板代码

1. 工程结构(下载模板

详细代码结构如下所示:

Course├──commons│  ├──commonlib/src/main/ets                              // 基础模块             │  │    ├──components│  │    │   ├──BottomEditBar.ets                          // 底部编辑组件│  │    │   ├──CourseItemComponent.ets                    // 课程列表组件│  │    │   ├──DeleteDialog.ets                           // 删除按钮组件│  │    │   ├──DialogComponent.ets                        // 自适应弹框组件│  │    │   ├──GlobalAttributeModifier.ets                // 自定义动态属性│  │    │   ├──LeftSwipeComponent.ets                     // 编辑组件│  │    │   ├──NoData.ets                                 // 空数据页面│  │    │   └──TopBar.ets                                 // 标题栏               │  │    ├──constants  │  │    │   ├──CommonConstants.ets                        // 常量│  │    │   └──CommonEnums.ets                            // 路由页面         │  │    ├──models  │  │    │   ├──CollectionModel.ets                        // 收藏│  │    │   ├──DownloadModel.ets                          // 下载│  │    │   ├──MyCourseModel.ets                          // 我的课程│  │    │   ├──OrderInfo.ets                              // 订单数据模型│  │    │   ├──TopicItemModel.ets                         // 题目数据模型│  │    │   ├──UserInfo.ets                               // 用户信息│  │    │   ├──WindowSize.ets                             // 窗口数据模型│  │    │   └──WrongQuestionModel.ets                     // 错题数据模型                           │  │    └──utils  │  │        ├──DialogUtil.ets                             // 弹框│  │        ├──Logger.ets                                 // 日志│  │        ├──NumberUtil.ets                             // 数据格式化│  │        ├──PermissionUtil.ets                         // 权限│  │        ├──PreferenceUtil.ets                         // 首选项│  │        └──RouterModule.ets                           // 路由 │  ││  │ │  └──http/src/main/ets                                   // 网络模块       │       ├──apis│       │    ├──Apis.ets                                  // 请求接口│       │    └──HttpRequest.ets                           // 请求对象│       ├──mocks  │       │    ├──AxiosMock.ets                             // mock│       │    ├──RequestMock.ets                           // 请求mock数据│       │    └──Data│       │         └──CourseData.ets                       // 数据源│       ├──model  │       │   └──CourseModel.ets                            // 课程数据模型         │       ├──tools  │       │   └──ConvertTool.ets                            // 模型转换工具                           │       └──types  │           └──Course.ets                                 // 课程数据协议 ├──components│  ├──aggregated_payment                                       // 支付组件                     │  ├──aggregated_share                                     // 分享组件│  ├──classification                                       // 分类组件 │  ├──feed_back                                            // 意见反馈组件│  ├──login_info                                           // 登录组件│  ├──open_ads                                             // 广告组件│  ├──search                                               // 搜索组件│  └──recorded_player                                      // 视频播放组件            ├──features                │  ├──course/src/main/ets                                  // 学习课程模块             │  │    ├──component│  │    │   └──CourseStudyComponent.ets                    // 课程数据源                │  │    ├──viewModels│  │    │   └──CourseVM.ets                                // 课程数据源                │  │    └──views │  │        └──MyLearnPage.ets                             // 学习页面              │  ││  ├──home/src/main/ets                                    // 首页模块     │  │    ├──components│  │    │   ├──AnswerQuestionsComponent.ets                // 答题view│  │    │   ├──CommentPopup.ets                            // 评分弹框│  │    │   ├──CourseCatalogComponents.ets                 // 课程章节弹框│  │    │   ├──LiveBroadcastSign.ets                       // 直播标签view│  │    │   ├──LiveNumberOverlay.ets                       // 数量view│  │    │   ├──LiveStreamingItem.ets                       // 直播列表item│  │    │   ├──AnswerSheetDialog.ets                       // 答题卡view│  │    │   └──HomeTop.ets                                 // 首页职能类型选择页面      │  │    ├──models│  │    │   ├──Practice.ets                                // 模块数据│  │    │   ├──HomeMenuModel.ets                           // 课程数据│  │    │   ├──SelectRoleModel.ets                         // 职称级别数据│  │    │   └──Score.ets                                   // 打分数据            │  │    ├──viewModels│  │    │   ├──CourseCatalogVM.ets                         // 章节数据刷新│  │    │   └──HomeVM.ets                                  // 首页数据刷新               │  │    └──pages│  │        ├──AnswerQuestionsExamPage.ets                 // 答题页面│  │        ├──AnswerQuestionsPage.ets                     // 答题view│  │        ├──AnswerSheetPage.ets                         // 答题卡页面│  │        ├──ChapterDetail.ets                           // 章节详情页面│  │        ├──CourseListPage.ets                          // 课程页页面│  │        ├──ExamResultPage.ets                          // 答题结果页面│  │        ├──HomePage.ets                                // 首页│  │        ├──HomeSearch.ets                              // 搜索页面│  │        ├──LiveStreamingListPage.ets                   // 直播页面│  │        ├──MaterialPage.ets                            // 资料页面│  │        ├──TestReportPage.ets                          // 结果页面│  │        └──RecordedDetail.ets                          // 课程详情页面  │  └──mine/src/main/ets                                    // 个人模块      │       ├──viewModel│       │   └──MyVM.ets                                    // 数据处理层                      │       ├──models│       │   ├──MessageModel.ets                            // 消息数据│       │   ├──SystemMessageModel.ets                      // 系统消息数据│       │   └──ServiceModel.ets                            // 模块服务数据     │       ├──component│       │   ├──CourseHistoryComponent.ets                  // 观看记录item│       │   └──TopicItemComponent.ets                      // 题目标题     │       └──views│           ├──AboutAndVersion.ets                         // 关于页面│           ├──AboutPage.ets                               // 设置页面│           ├──Authentication.ets                          // 用户协议页面│           ├──CourseUpdateMessagePage.ets                 // 课程动态消息页面│           ├──DataSharingPage.ets                         // 三方信息页面│           ├──FeedbackPage.ets                            // 意见反馈页面│           ├──FeedbackRecordsPage.ets                     // 反馈记录│           ├──MessageListCard.ets                         // 消息列表组件页面│           ├──MessagePage.ets                             // 消息页面│           ├──MinePage.ets                                // 个人页面│           ├──MultiLineText.ets                           // 消息组件页面│           ├──MyCollectionPage.ets                        // 收藏页面│           ├──MyCourseComments.ets                        // 课程评论页面│           ├──MyCoursePage.ets                            // 课程页面│           ├──MyDownloadPage.ets                          // 下载页面│           ├──MyOrderPage.ets                             // 订单页面│           ├──MyWrongQuestionPage.ets                     // 错题页面│           ├──OrderListPage.ets                           // 订单列表页面│           ├──OrderDetailPage.ets                         // 订单列表页面│           ├──PersonalInfoPage.ets                        // 个人信息页面│           ├──PersonalInformationCollectionPage.ets       // 个人信息收集页面│           ├──PrivacyAgreement.ets                        // 隐私协议页面│           ├──PrivacySetPage.ets                          // 隐私设置页面│           ├──PrivacyStatement.ets                        // 隐私声明页面│           ├──SetUpPage.ets                               // 设置页面│           ├──SystemMessage.ets                           // 系统消息页面│           ├──UpdateVersionContentCard.ets                // 版本更新页面│           ├──WatchHistoryPage.ets                        // 观看记录页面│           └──UserAgreement.ets                           // 服务协议页面   └──product   └──entry/src/main/ets            ├──viewmodels                                      // 首页数据        │   └──MainEntryVM.ets            ├──entryability                                    // 入口        │   └──EntryAbility.ets                                               ├──entrybackupability                              // 后台        │   └──EntryBackupAbility.ets                ├──models                     │   ├──RouterTable.ets                             // 路由表        │   └──Types.ets                                   // tab数据类型        └──pages              ├──Index.ets                                    // 入口页面           ├──Launch.ets                                   // 启动页面           ├──LaunchAd.ets                                 // 广告页面           ├──Login.ets                                    // 登录页面           ├──MainEntry.ets                                // 主页面           ├──PrivacyPolicy.ets                            // 隐私页面           └──PrivacyPolicyAlert.ets                       // 隐私弹框页面
复制代码
2. 关键代码解读

本篇代码非应用的全量代码,只包括应用的部分能力的关键代码。

1) 播放器工具封装

@ObservedV2export class AVPlayer {  callbackComplete: () => void = () => {  };  callbackTimeUpdate: (nol: number, total: number) => void = (nol: number) => {  };  callbackBitrateUpdate: (bitrateList: number[]) => void = (bitrateList: number[]) => {  };  callbackErrorUpdate: (error: string) => void = (error: string) => {  };  @Trace currentTime: number = 0;  @Trace totalDuration: number = 0;  @Trace isPlaying: boolean = false;  @Trace isLoading: boolean = true;  @Trace isLoadError: boolean = false;  // surfaceID用于播放画面显示,具体的值需要通过XComponent接口获取,相关文档链接见上面XComponent创建方法  surfaceID: string = '';  // 画中画是否开启  isPipOpen: boolean = false;  // 复原  isPiPWindowRestore: boolean = false;  avPlayer: media.AVPlayer = {} as media.AVPlayer;  isCreate: boolean = false;  seekTime: number = 0;  // 碰到特殊场景进入其他页时,即便加载成功也不需要播放  isResetPause: boolean = false;  videoUrl: string = '';
async init(url: string, seekTime: number): Promise<void> { await this.release(); // 创建avPlayer实例对象 this.avPlayer = await media.createAVPlayer(); // 创建状态机变化回调函数 await this.setStateChangeCallback(); await this.setSourceInfoCallback(); this.isCreate = true; this.isResetPause = false; this.videoUrl = url this.avPlayer.url = url; this.isLoading = true; this.seekTime = seekTime; }
getPlay() { if (this.avPlayer) { this.avPlayer.play(); } }
getPause() { if (this.avPlayer) { this.avPlayer.pause(); } }
getStop() { if (this.avPlayer) { this.avPlayer.stop(); } }
changeVolume(volume: number) { if (this.avPlayer) { this.avPlayer.setVolume(volume) } }
changeSpeed(speed: number) { if (this.avPlayer) { this.avPlayer.setSpeed(speed) } }
changeSeek(seekTime: number, mode: SliderChangeMode) { if (this.avPlayer) { this.avPlayer.seek(seekTime, 2); } }
setSurfaceId(surfaceId: string): void { if (this.avPlayer.surfaceId === surfaceId) { return } this.surfaceID = surfaceId this.avPlayer.surfaceId = this.surfaceID; }
// 切换播放 async changePlay(url: string, seekTime: number) { if (this.avPlayer) { setTimeout(() => { this.isLoadError = false }, 1000) this.isPlaying = false this.isLoading = true this.isResetPause = false; await this.avPlayer.reset() this.totalDuration = 0 this.seekTime = seekTime this.videoUrl = url this.avPlayer.url = url } }
setCompleteCallback(func: () => void) { this.callbackComplete = func; this.isPlaying = false }
setTimeUpdateCallback(func: (nol: number, total: number) => void) { this.callbackTimeUpdate = func; }
setBitrateUpdateCallback(func: (bitrateList: number[]) => void) { this.callbackBitrateUpdate = func; }
setErrorCallback(func: (error: string) => void) { this.callbackErrorUpdate = func; }
// 资源释放 async release() { if (this.isCreate) { this.isCreate = false; this.isPlaying = false; this.isLoading = false; this.isLoadError = false; this.isResetPause = false; await this.avPlayer.release(); } }
// 视频信息上报函数 async setSourceInfoCallback(): Promise<void> { // 时间上报函数 this.avPlayer.on('timeUpdate', (time: number) => { this.currentTime = time this.callbackTimeUpdate(time, this.totalDuration); }); // 音量变化回调函数 this.avPlayer.on('volumeChange', (vol: number) => { }); // 视频播放结束触发回调 this.avPlayer.on('endOfStream', () => { }); // seek操作回调函数 this.avPlayer.on('seekDone', (seekDoneTime: number) => { }); // 视频总时长上报函数 this.avPlayer.on('durationUpdate', (duration: number) => { }); // 设置倍速播放回调函数 this.avPlayer.on('speedDone', (speed: number) => { }); // bitrate设置成功回调函数 this.avPlayer.on('bitrateDone', (bitrate: number) => { }); // 缓冲上报回调函数 this.avPlayer.on('bufferingUpdate', (infoType: media.BufferingInfoType, value: number) => { }); // 首帧上报回调函数 this.avPlayer.on('startRenderFrame', () => { }); // 视频宽高上报回调函数 this.avPlayer.on('videoSizeChange', (width: number, height: number) => { }); // 焦点上报回调函数 this.avPlayer.on('audioInterrupt', (info: audio.InterruptEvent) => { }); // HLS上报所有支持的比特率 this.avPlayer.on('availableBitrates', (bitrates: number[]) => { this.callbackBitrateUpdate(bitrates); }); // 设置错误监听 this.avPlayer.on('error', (error) => { this.callbackErrorUpdate('Error ' + error.code + ' - ' + error.message); }); }
// 状态机 async setStateChangeCallback(): Promise<void> { this.avPlayer.on('stateChange', async (state: string, reason: media.StateChangeReason) => { if (this.avPlayer == null) { return; } switch (state) { // 闲置状态,成功调用reset接口后触发该状态机上报 case AVPlayerState.IDLE: this.isLoadError = false break; // 资源初始化,avplayer设置播放源后触发该状态上报 case AVPlayerState.INITIALIZED: if (this.surfaceID) { this.setSurfaceId(this.surfaceID); // 设置显示画面,当播放的资源为纯音频时无需设置 this.avPlayer.prepare(); // 进入准备状态 } break; // 已准备状态 case AVPlayerState.PREPARED: this.avPlayer.audioInterruptMode = audio.InterruptMode.INDEPENDENT_MODE; this.totalDuration = this.avPlayer.duration; this.currentTime = this.totalDuration * this.seekTime / 100 this.avPlayer.seek(this.currentTime, 2); if (this.isResetPause) { this.isPlaying = false; this.avPlayer.pause() }else { this.isPlaying = true; this.avPlayer.play(); } this.changeSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_00_X) this.isLoadError = false; break; // 正在播放状态 case AVPlayerState.PLAYING: this.isLoading = false; this.isPlaying = true; break; // 暂停状态 case AVPlayerState.PAUSED: this.isLoading = false; this.isPlaying = false; break; // 播放至结尾状态 case AVPlayerState.COMPLETED: this.isPlaying = false this.callbackComplete(); break; // 停止状态 case AVPlayerState.STOPPED: break; // 销毁状态,销毁与当前AVPlayer关联的播放引擎,无法再进行状态转换 case AVPlayerState.RELEASED: this.isLoading = true; break; // 错误状态,当播放引擎发生不可逆的错误,则会转换至当前状态 case AVPlayerState.ERROR: setTimeout(() => { this.isPlaying = false; this.isLoading = false; this.isLoadError = true; }, 1000) break; default: break; } }) }}
复制代码


2) 画中画工具类封装

const CONTEXT_WIDTH: number = 1600;const CONTEXT_HEIGHT: number = 900;
export class CustomXComponentController extends XComponentController { onSurfaceCreated(surfaceId: string): void { if (PipManager.getInstance().player.surfaceID === surfaceId) { return; } PipManager.getInstance().player.setSurfaceId(surfaceId); }}
// 画中画控制器export class PipManager { private static instance: PipManager = new PipManager(); private pipController?: PiPWindow.PiPController; private mXComponentController: XComponentController; player: AVPlayer;
constructor() { this.player = new AVPlayer(); this.mXComponentController = new CustomXComponentController(); }
public static getInstance(): PipManager { return PipManager.instance; }
getXComponentController(): CustomXComponentController { return this.mXComponentController; }
init(ctx: Context, navigationId: string) { // 当前设备如若不支持画中画则退出 if (!PiPWindow.isPiPEnabled()) { return; } let config: PiPWindow.PiPConfiguration = { context: ctx, // XComponent组件绑定同一个 componentController: this.mXComponentController, navigationId: navigationId, // 画中画媒体类型枚举,当前使用的视频播放模版 templateType: PiPWindow.PiPTemplateType.VIDEO_PLAY, contentWidth: CONTEXT_WIDTH, contentHeight: CONTEXT_HEIGHT, }; PiPWindow.create(config).then((controller: PiPWindow.PiPController) => { this.pipController = controller; this.pipController?.setAutoStartEnabled(false); this.pipController.on('stateChange', (state: PiPWindow.PiPState, reason: string) => { this.onStateChange(state, reason); }); this.pipController.on('controlEvent', (control: PiPWindow.ControlEventParam) => { this.onActionEvent(control); }); }).catch((err: BusinessError) => { }) }
startPip() { this.pipController?.startPiP().then(() => { }).catch((err: BusinessError) => { }); }
stopPip() { this.pipController?.stopPiP().then(() => { }).catch((err: BusinessError) => { }); }
setAutoStart(autoStart: boolean): void { this.pipController?.setAutoStartEnabled(autoStart); }
updateContentSize(width: number, height: number) { if (this.pipController) { this.pipController.updateContentSize(width, height); } }
updatePiPControlStatus() { let controlType: PiPWindow.PiPControlType = PiPWindow.PiPControlType.VIDEO_PLAY_PAUSE; let status: PiPWindow.PiPControlStatus = PiPWindow.PiPControlStatus.PLAY; this.pipController?.updatePiPControlStatus(controlType, status); }
unregisterPipStateChangeListener() { this.pipController?.off('stateChange'); this.pipController?.off('controlEvent'); }
// 监听画中画生命周期 onStateChange(state: PiPWindow.PiPState, _reason: string) { switch (state) { // 表示画中画将要启动 case PiPWindow.PiPState.ABOUT_TO_START: break; // 表示画中画已经启动 case PiPWindow.PiPState.STARTED: // 启动画中画 PipManager.getInstance().player.isPipOpen = true; break; // 表示画中画将要停止 case PiPWindow.PiPState.ABOUT_TO_STOP: // 画中画关闭 PipManager.getInstance().player.isPipOpen = false; break; // 表示画中画已经停止 case PiPWindow.PiPState.STOPPED: // 画中画关闭 PipManager.getInstance().player.isPipOpen = false; // // 小窗口点击关闭画中画,视频暂停播放 PipManager.getInstance().player.isPiPWindowRestore = false; break; // 表示画中画将从小窗播放恢复到原始播放界面 case PiPWindow.PiPState.ABOUT_TO_RESTORE: // 小窗口复原关闭画中画 PipManager.getInstance().player.isPipOpen = false; // 从小窗口复原 PipManager.getInstance().player.isPiPWindowRestore = true; break; // 表示画中画生命周期执行过程出现了异常 case PiPWindow.PiPState.ERROR: break; default: break; } }
// 监听画中画控制面板控件动作事件 onActionEvent(control: PiPWindow.ControlEventParam) { switch (control.controlType) { // 视频播放、停止 case PiPWindow.PiPControlType.VIDEO_PLAY_PAUSE: if (control.status === PiPWindow.PiPControlStatus.PAUSE) { // 停止视频 PipManager.getInstance().player.isPlaying = false; } else if (control.status === PiPWindow.PiPControlStatus.PLAY) { // 播放视频 PipManager.getInstance().player.isPlaying = true; } break; // 切换到下一个视频 case PiPWindow.PiPControlType.VIDEO_NEXT: break; // 切换到上一个视频 case PiPWindow.PiPControlType.VIDEO_PREVIOUS: break; // 视频进度快进 case PiPWindow.PiPControlType.FAST_FORWARD: break; // 视频进度后退 case PiPWindow.PiPControlType.FAST_BACKWARD: break; default: break; } }}
复制代码
3. 模板集成

本模板提供了两种代码集成方式,供开发者自由使用。

1) 整体集成

开发者可以选择直接基于模板工程开发自己的应用工程。

  • 模板代码获取:

① 通过 IDE 插件创建模板工程,开发指导

② 通过生态市场下载源码, 下载模板

③ 通过开源仓访问源码,仓库地址

  • 打开模板工程,根据 README 说明中的快速入门章节,将自己的应用信息配置在模板工程内,即可运行并查看模板效果。


 

  • 对接开发者自己的服务器接口,转换数据结构,展示真实的云侧数据。

将 commons/http/src/main/ets/apis/Apis.ets 文件中的 mock 接口替换为真实的服务器接口。


 

在 commons/http/src/main/ets/types/Course.ets 文件中将云侧开发者自定义的数据结构转换为端侧数据结构。


 

  • 根据自己的业务内容修改模板,进行定制化开发。

 

2) 按需集成

若开发者已搭建好自己的应用工程,但暂未实现其中的部分场景能力,可以选择取用其中的业务组件,集成在自己的工程中。

  • 组件代码获取:

① 通过 IDE 插件下载组件源码。开发指导

② 通过生态市场下载组件源码。 下载地址


  • 下载组件源码,根据 README 中的说明,将组件包配置在自己的工程中。

  • 根据 API 参考和示例代码,将组件集成在自己的对应场景中。


以上是第 10 期“课堂应用”行业优秀案例的内容,更多行业敬请期待~

欢迎下载使用行业模板“点击下载”,若您有体验和开发问题,或者迫不及待想了解 XX 行业的优秀案例,欢迎在评论区留言,小编会快马加鞭为您解答~

同时诚邀您添加下方二维码加入“组件模板活动社群”,精彩上新 &活动不错过!

👉 HarmonyOS 官方模板优秀案例系列持续更新, 点击查看往期案例汇总贴,点击收藏,方便查找!

👉【集成有礼】HarmonyOS 官方模板集成创新活动,挥洒创意,赢精美大礼!点击参加

👉【HarmonyOS 行业解决方案】为各行业鸿蒙应用提供全流程技术方案。点击查看

2025-10-28 15:213

评论

发布
暂无评论

百度智能云助力自动驾驶全链路研发

Baidu AICLOUD

自动驾驶 全链路

随机高并发查询结果一致性设计实践

京东科技开发者

架构设计 并发 业务场景 企业号 2 月 PK 榜 京东物流

软件测试/测试开发 | app自动化测试(Android)--显式等待机制

测试人

软件测试 自动化测试 测试开发 appium app自动化测试

1 理解功能、业务功能和能力

涛哥 数字产品和业务架构

企业架构 业务架构 业务架构师

为什么我在公司里访问不了家里的电脑?

Java 计算机网络 网络协议

过年回去,终于给老人讲清楚两台电脑是如何通信的

华为云开发者联盟

后端 开发 华为云 企业号 2 月 PK 榜 华为云开发者联盟

国资委79号文解读:国央企OA办公系统信创替代落地实践与标杆案例

数字科技时讯

信创 电子合同 电子签名 企业国产化 OA

零基础前端培训学习有用吗

小谷哥

OpenMLDB 社区月报 | 2023 年 1 月

第四范式开发者社区

人工智能 机器学习 数据库 开源 特征

详解 k8s 中的 RBAC

HummerCloud

云原生 k8s

2024最新easyrecovery数据恢复软件免费版

茶色酒

EasyRecovery15

顶会论文 | 虚拟网络探测技术的探索与实践

阿里技术

网络运维 虚拟网络探测

城市健康云,打造大健康服务生态

华为云开发者联盟

云计算 后端 华为云 企业号 2 月 PK 榜 华为云开发者联盟

自动驾驶工具链及仿真平台的应用

Baidu AICLOUD

自动驾驶 工具链

跨境电商“重新出发”,区块链赋能新玩法

旺链科技

区块链 区块链技术 区块链技术应用

2023 年推荐这 10 个开发者工具

Liam

前端 后端 开发者工具 开发工具 程序员 java

奇安信首次盈利,网络安全国家队将迎来收获期?

ToB行业头条

网络安全

采购LED显示屏时必须了解哪些技术参数?

Dylan

LED显示屏 全彩LED显示屏 led显示屏厂家

打造合规数据闭环,加速自动驾驶技术研发

Baidu AICLOUD

自动驾驶 数据闭环

手把手教您在PyCharm中连接云端资源进行代码调试

华为云开发者联盟

人工智能 华为云 企业号 2 月 PK 榜 华为云开发者联盟

StarRocks市场渗透率跻身Top10!

StarRocks

数据库

会声会影2023中文版操视频剪辑软件下载

茶色酒

会声会影2023

TiDB 6.5 新特性解析丨过去一年,我们是如何让 TiFlash 高效又稳定地榨干 CPU?

PingCAP

TiDB

特定领域知识图谱融合方案:文本匹配算法(Simnet、Simcse、Diffcse)

汀丶人工智能

自然语言处理 知识图谱 2月日更

StarRocks荣获开源中国“2022 年度优秀开源技术团队”

StarRocks

数据库

如何解决Mac电脑突然变得又卡又慢的处理方法

茶色酒

开发小白的高光逆袭:竟然能一眼断定生产环境接口响应时间慢是磁盘性能问题引起的

KINDLING

Java 故障定位 ebpf 生产环境 排障

PingCAP 黄东旭万字长文剖析数据库发展新趋势:脱离应用开发者的数据库,不会成功

PingCAP

数据库 TiDB

重塑设备维护管理的主要趋势

PreMaint

设备健康管理 设备管理

如何将使用中的域名平滑迁移到京东云?(以原域名注册、域名解析都在万网为例)

京东科技开发者

域名解析 注册 京东云 京东商城 企业号 2 月 PK 榜

软件测试/测试开发 | app自动化测试(Android)--触屏操作自动化

测试人

软件测试 自动化测试 测试开发 appium

【案例+1】HarmonyOS官方模板优秀案例  (第10期:教育行业·课堂应用)_HarmonyOS_HarmonyOS_InfoQ精选文章