写点什么

【案例 +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:211252

评论

发布
暂无评论

我们用GLM-4-Plus搞了个“阅读智能体”,工作效率提升了300%

Alter

乘风破浪!天翼云为出海企业打造全球云服务解决方案!

天翼云开发者社区

云计算 IDC

与南方航空牵手合作,望繁信科技朋友圈再扩大!

望繁信科技

数字化转型 流程挖掘 流程资产 流程智能 望繁信科技

JavaScript 异步编程入门

FunTester

大数据之数据治理体系全面指南

五分钟学大数据

大数据 数据治理

《使用Gin框架构建分布式应用》阅读笔记:p1-p19

codists

gin

Docker-Compose 应用可观测性最佳实践

观测云

Docker-compose

鸿蒙开发案例:通过三杯猜球学习显示动画

zhongcx

OKR实践之——重要紧急矩阵

Bruce Talk

OKR 敏捷开发

3DCAT实时云渲染赋能2024广东旅博会智慧文旅元宇宙体验馆上线!

3DCAT实时渲染

实时云渲染 元宇宙解决方案 智慧文旅元宇宙 元宇宙体验馆

API在电商之中的作用是什么?

秃头小帅oi

AIGCDesign 开放式跨端 AI 组件解决方案

京东零售技术

前端 AIGC

引领行业数字变革,天翼云出席IDC年度盛典暨颁奖典礼!

天翼云开发者社区

云计算 IDC

公司党委书记、董事长、总经理胡志强出席“国企改革大家谈”分享天翼云改革经验

天翼云开发者社区

云计算 天翼云

构建一体化解决方案:天谋科技与美林数据完成兼容性互认证

Apache IoTDB

Java实现加入购物车怎么做数据定位?

威哥爱编程

Java JavaEE 购物车项目

Docker部署PhotoPrism、Immich图片管理应用,无需公网IP远程访问教程

贝锐

NAS Docker 镜像

草料二维码产品更新速览!优化二维码标签下载弹窗、企业专属独立登录页等

草料二维码

无代码平台 草料二维码 草料二维码无代码

低代码开发平台开启智能制造新工具时代

不在线第一只蜗牛

低代码 制造业

天翼云完成首个国产化万卡训练,MFU达到国内领先水平!

天翼云开发者社区

云计算 云服务 云平台 天翼云

引领科技未来,助力产业发展——成都远川科技有限公司

极客天地

一张图带你了解.NET终结(Finalize)流程

不在线第一只蜗牛

.net

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