#星光不负 码向未来# 鸿蒙北京站实操工坊纪实 原创

行走江湖拎壶冲
发布于 2025-10-21 19:13
浏览
0收藏

#星光不负 码向未来# 鸿蒙北京站实操工坊:从赛题实战到技术成长的完整记录

一、活动背景

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_StartingPoint07_Resources文件夹(均创建于2024/6/16 11:50)。

2. 实操步骤与核心代码

  • 步骤1:本地资源部署
    07_Resourcescourse_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_StartingPoint10_Resources文件夹(10_StartingPoint创建于2024/6/19 16:21)。文档强调,该功能依赖textToSpeech模块,模拟器不支持,需用真机测试。

2. 核心实现步骤

  • 步骤1:封装语音模块
    commons/utils/src/main/ets/utils创建Speaker.ets,导入textToSpeechemitter依赖,定义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_StartingPointQS11_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新特性,基于本次实操经验开发更多项目,在“一次开发,多端部署”的道路上持续探索,为鸿蒙生态贡献自己的力量。星光不负赶路人,每一次实操都是成长的阶梯,我期待在鸿蒙生态中遇见更好的自己。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
收藏
回复
举报
回复
    相关推荐