
#星光不负 码向未来# 鸿蒙北京站实操工坊纪实 原创
#星光不负 码向未来# 鸿蒙北京站实操工坊:从赛题实战到技术成长的完整记录
一、活动背景
2025年10月18日,我参与了HDD·鸿蒙赋能交流会 实操工坊-北京站活动,这是我首次接触鸿蒙线下技术实操场景。
活动以“鸿蒙组件实战与多端适配”为核心,提供了从基础到高阶的完整赛题体系,搭配详细教程与资源支持,旨在帮助开发者快速掌握鸿蒙应用开发关键能力。
活动当天虽历经小波折——早高峰打车难、共享电动车半路因超出营运范围断电、最终靠地铁赶场,但10:30准时抵达现场后,工作人员的有序引导(签到、信息填写、分组)与现场浓厚的技术交流氛围,迅速打消了赶路的疲惫。
午餐时段,工作组准备了免费盒饭,开发者们边用餐边讨论鸿蒙组件使用技巧,这种“沉浸式学习”的氛围,让我对后续实操环节充满期待。
二、赛题解析与实战过程
本次活动赛题严格围绕给参赛者的邮件里面的内容来进行的设置,分为初阶赛题与高阶赛题两类,共4道任务,每道题均提供配套资源文件夹与详细步骤指引,确保开发者能循序渐进完成实操。
(一)初阶赛题1:使用常见组件构建页面——创建“赋能套件”网格视图Item
1. 赛题要求
需使用Grid组件实现赋能套件列表的横向一行展示,核心是构建包含“文章标题、文章简介、文章配图”的单个网格Item视图(对应文档图1),并掌握自定义组件创建、资源引用与布局优化的方法。
2. 实操步骤与核心代码
-
步骤1:项目初始化
选择从“上一教程结束时的项目”或直接运行03_StartingPoint
文件夹中的项目(该文件夹创建时间为2024/6/19 16:21,包含README.md文件),同时使用03_Resources
文件夹(2024/6/16 11:50创建)中的资源文件。 -
步骤2:创建自定义组件
在src/main/ets/pages/Index.ets
文件中,定义名为EnablementItem
的自定义组件,并用@Preview
装饰器实现单独预览,代码框架如下:// src/main/ets/pages/Index.ets @Preview @Component struct EnablementItem { // 定义私有文本属性:仅组件内使用,示例文本与文档一致 private title: string = 'HarmonyOS第一课'; private brief: string = '基于真实的开发场景,提供向导式学习,多维度融合课程等内容,给开发者提供全新的学习体验。'; build() { // 外层容器:Column实现垂直布局,设置宽高、圆角与背景 Column() { // 步骤3:引入图片资源 Image($r('app.media.enablement_pic1')) .width('100%') .height(96) .objectFit(ImageFit.Cover) // 保持宽高比填充 .borderRadius({ topLeft: 16, topRight: 16 }) // 仅顶部圆角,与容器匹配 // 步骤4:添加标题文本 Text(this.title) .width('100%') .height(19) .fontSize(14) .fontWeight(400) .textAlign(TextAlign.Start) .textOverflow({ overflow: TextOverflow.Ellipsis }) // 超长省略 .maxLines(1) .padding({ left: 12, right: 12 }) // 步骤5:添加简介文本 Text(this.brief) .width('100%') .height(32) .fontSize(12) .fontColor('rgba(0, 0, 0, 0.6)') .textOverflow({ overflow: TextOverflow.Ellipsis }) .maxLines(2) .padding({ left: 12, right: 12 }) .margin({ top: 2 }) } .width(160) .height(169) .borderRadius(16) .backgroundColor(Color.White) } }
-
关键注意点
需将03_Resources
中的enablement_pic1.png
放入entry/src/main/resources/base/media
路径;文档特别强调,实际开发中应将字符串资源统一存放在src/main/resources/base/element/string.json
,通过$r('app.type.name')
引用,便于多端适配与国际化。
(二)初阶赛题2:构建更丰富的界面——ArkWeb页面适配
1. 赛题要求
根据文档,需使用Web组件实现CourseLearning
页面加载html页面,掌握“网络页面加载、本地页面加载、网络权限配置”三大核心能力,配套资源为07_StartingPoint
与07_Resources
文件夹(均创建于2024/6/16 11:50)。
2. 实操步骤与核心代码
-
步骤1:本地资源部署
将07_Resources
中course_learning
目录(含index.html
)放入features/learning/src/main/resources/rawfile
目录(目录不存在需自行创建),文档提示可先双击index.html
用浏览器预览效果,建议开启“设备工具栏”(F12打开控制台)模拟不同屏幕尺寸。 -
步骤2:配置网络权限
在products/default/src/main/module.json5
中申请网络权限,同时在多语言string.json
中添加权限说明:// products/default/src/main/module.json5 "module": { "requestPermissions": [ { "name": "ohos.permission.INTERNET", "reason": "$string:apply_for_network" } ] } // 中文权限说明(zh_CN/element/string.json) "string": [ { "name": "apply_for_network", "value": "允许应用使用网络" } ] // 英文权限说明(en_US/element/string.json) "string": [ { "name": "apply_for_network", "value": "Allow the app to access the network" } ]
-
步骤3:实现Web组件加载逻辑
在features/learning/src/main/ets/pages
创建CourseLearning.ets
,通过webview.WebviewController
控制页面加载,代码如下:import { webview } from '@kit.ArkWeb'; @Component export struct CourseLearning { // 创建控制器实例,用于管理Web组件 private webviewController: webview.WebviewController = new webview.WebviewController(); build() { Column() { // 加载本地页面:引用rawfile目录下的html文件 Web({ src: $rawfile('course_learning/index.html'), controller: this.webviewController }) .domStorageAccess(true) // 开启DOM存储权限,确保页面交互正常 // 加载网络页面(示例:华为官网,文档提示需真机/模拟器验证) // Web({ src: 'http://www.huawei.com', controller: this.webviewController }) // .domStorageAccess(true) } } }
-
关键注意点
文档明确指出,Web组件暂不支持Previewer预览,必须在真机或模拟器上运行;同时需在features/learning/Index.ets
中导出CourseLearning
组件,供其他模块引用。
(三)高阶赛题1:鸿蒙智能——AI语音朗读
1. 赛题要求
需补充创建播报引擎逻辑,实现“文本转语音”功能,支持文章简介朗读,配套资源为10_StartingPoint
与10_Resources
文件夹(10_StartingPoint
创建于2024/6/19 16:21)。文档强调,该功能依赖textToSpeech
模块,模拟器不支持,需用真机测试。
2. 核心实现步骤
-
步骤1:封装语音模块
在commons/utils/src/main/ets/utils
创建Speaker.ets
,导入textToSpeech
与emitter
依赖,定义Speaker
类存储引擎实例:import { textToSpeech } from '@kit.CoreSpeechKit'; import { BusinessError, emitter } from '@kit.BasicServicesKit'; export class Speaker { ttsEngine?: textToSpeech.TextToSpeechEngine; // 播报引擎实例 speakListener?: textToSpeech.SpeakListener; // 播报状态监听 // 引擎初始化参数:中文(zh-CN)、在线模式(1)、聆小珊音色(0) initParamsInfo: textToSpeech.CreateEngineParams = { language: 'zh-CN', person: 0, online: 1, extraParams: { "style": 'interaction-broadcast', "locate": 'CN', "name": 'EngineName' } }; // 构造函数:初始化监听与引擎 constructor() { this.initListener(); this.createEngine(); } // 步骤2:初始化播报状态监听(开始、完成、停止等回调) initListener() { this.speakListener = { onStart(requestId: string, response: textToSpeech.StartResponse) {}, onComplete(requestId: string, response: textToSpeech.CompleteResponse) { if (response.type === 1) emitter.emit("eventId"); // 播报完成触发事件 }, onStop(requestId: string, response: textToSpeech.StopResponse) { if (response.type === 1) emitter.emit("eventId"); }, onData(requestId: string, audio: ArrayBuffer, response: textToSpeech.SynthesisResponse) {}, onError(requestId: string, errorCode: number, errorMessage: string) {} }; } // 步骤3:创建引擎实例并绑定监听 createEngine() { try { textToSpeech.createEngine(this.initParamsInfo, (err: BusinessError, engine) => { if (!err) { this.ttsEngine = engine; this.ttsEngine.setListener(this.speakListener); } }); } catch (error) { const err = error as BusinessError; console.error(`引擎创建失败:${err.code} - ${err.message}`); } } // 步骤4:实现播报控制方法 startSpeak(content: string) { const speakParams: textToSpeech.SpeakParams = { requestId: Date.now().toString(), // 全局唯一ID extraParams: { "queueMode": 0, "speed": 1, "volume": 2, "pitch": 1 } // 排队模式、最大音量 }; this.ttsEngine?.speak(content, speakParams); } stopSpeak() { this.ttsEngine?.stop(); } shutdownEngine() { this.ttsEngine?.shutdown(); } // 组件销毁时释放资源 }
-
步骤5:页面中调用语音功能
在ArticleDetailPage.ets
中创建Speaker
实例,通过点击图标控制播报启停,文档提示需在aboutToDisappear
中调用shutdownEngine
释放资源。
(四)高阶赛题2:一次开发,多端部署
1. 赛题要求
需实现Tabs、Swiper、List、Navigation组件的多端适配,支持手机、平板、折叠屏等设备,核心是通过“断点”划分设备宽度区间,配套资源为QS11_StartingPoint
与QS11_Resources
文件夹(QS11_StartingPoint
创建于2024/4/23 20:42)。
2. 核心实现逻辑
-
步骤1:理解断点概念
文档定义了标准断点区间:sm
([320,600)vp)、md
([600,840)vp)、lg
([840,+∞)vp),可扩展xl
断点([1500,+∞)vp)区分大屏设备。 -
步骤2:引入断点系统
将QS11_Resources
中的BreakpointSystem.ets
放入commons/utils/src/main/ets/utils
,并在commons/utils/index.ets
导出:export { BreakpointSystem, BreakpointTypeEnum, BreakpointType } from './src/main/ets/utils/BreakpointSystem';
-
步骤3:Tabs组件适配示例
在Index.ets
中注册断点监听,根据断点调整Tabs页签位置与方向:import { BreakpointSystem, BreakpointTypeEnum } from 'utils'; @Component struct Index { private breakpointSystem: BreakpointSystem = new BreakpointSystem(); @StorageProp('currentBreakpoint') currentBreakpoint: string = BreakpointTypeEnum.MD; aboutToAppear() { this.breakpointSystem.register(); } // 注册监听 aboutToDisappear() { this.breakpointSystem.unregister(); } // 解除监听 build() { Tabs({ // lg断点(平板)页签在左侧,其他断点在底部 barPosition: this.currentBreakpoint === BreakpointTypeEnum.LG ? BarPosition.Start : BarPosition.End, controller: this.tabsController }) { Tab('快速入门') { /* 内容 */ } Tab('课程学习') { /* 内容 */ } } .vertical(this.currentBreakpoint === BreakpointTypeEnum.LG ? true : false) // lg断点纵向显示 } }
-
其他组件适配
文档详细说明:Swiper通过displayCount
控制每页元素数(sm:1、md:2、lg:2),List通过lanes
控制列数(sm:1、md:2、lg:3),Navigation通过mode(NavigationMode.Auto)
自动切换单页/分栏模式。
三、活动总结与技术收获
本次实操工坊从初阶的组件创建到高阶的多端适配,形成了完整的技术学习闭环。活动倡导的“先完成者帮后完成者”模式,让我在遇到“图片圆角不匹配”“Web页面加载失败”等问题时,能及时获得同伴指导;颁奖环节中,工作组不仅为挑战题完成者准备大奖,也为基础题完成者提供纪念礼品,细节处体现对开发者的尊重。
今天早上的波折没有白费,今天我不仅掌握了鸿蒙核心组件的实战用法,更理解了“一次开发,多端部署”的设计理念——无需编写多套代码,仅通过断点适配即可实现全设备兼容。
而且还收获了工作组精心准备的礼物。
非常完美~
活动总结与收获
本次实操工坊让我从“理论认知”走向“实战落地”,不仅掌握了Grid、Web、Tabs等基础组件的使用,还初步探索了AI语音、多端适配等进阶能力。活动中的互助模式与技术分享,让我感受到鸿蒙开发者社区的活力。
未来,我会继续深入学习鸿蒙6.0新特性,基于本次实操经验开发更多项目,在“一次开发,多端部署”的道路上持续探索,为鸿蒙生态贡献自己的力量。星光不负赶路人,每一次实操都是成长的阶梯,我期待在鸿蒙生态中遇见更好的自己。
