【愚公系列】保姆级教程带你实现HarmonyOS手语猜一猜元服务

🚀前言

最近HarmonyOS NEXT大火,这个纯血鸿蒙吸引力了大家的关注。虽然现在还没面向个人开发者开放,但我们可以基于最新的API9及开发工具来尝试开发鸿蒙新的应用形态——元服务。来体验下未来在HarmonyOS NEXT上实现的应用开发。

HarmonyOS是华为公司开发的操作系统,它的设计理念是面向未来的全场景智慧体验,可在各种设备上运行,包括手机、平板电脑、智能手表、智能音箱等。HarmonyOS采用分布式技术,可以将不同设备之间的计算资源连接起来,实现设备间的协同工作,提高系统的性能和稳定性。此外,HarmonyOS还拥有高度自适应的界面、多屏协同等特性,使用户能够在不同设备上实现无缝的体验。

本文主要是基于手语学习元服务的开发案例:主要的功能有

  • 元服务内部功能:
    • 1、提供专业手语翻译老师示范视频,包括基本手势、字母表、常用短语等。用户可以点击观看示范并模仿。
    • 2、提供类似答题模块,帮助用户巩固所学的手语知识,用户可以完成答题模块测试自己的进步。
  • 元服务卡片:
    • 1、卡片界面展示每日一题,并可以在卡片上进行答题学习

项目实现效果如下:

元服务内部功能视频:

元服务卡片功能视频:

🚀一、HarmonyOS元服务简介

🔎1.什么是元服务

元服务(原名为原子化服务)是HarmonyOS提供的一种面向未来的服务提供方式。它是一种新型应用程序形态,具有独立入口、免安装的特点,可以为用户提供一个或多个便捷服务。

以线上购物为例,传统购物应用需要先安装应用,打开应用查找商品,加入购物车,然后完成支付。而通过元服务的方式,可以将购物过程拆分为多个服务,例如“商品浏览”、“购物车”、“支付”等,无需安装应用,通过丰富的入口直达服务页面。例如,将心仪的商品页添加到桌面,可以实时掌握商品价格的变动。在秒杀时间点,可以直接进入购物车进行结算。

元服务基于HarmonyOS API开发,为用户在合适的场景、合适的设备上提供便捷的使用体验。相比传统的需要安装的应用形态,元服务更加轻量,同时提供更丰富的入口和更精准的分发。它为用户提供了更灵活、更高效的服务方式,提升了用户体验和便利性。

🔎2.元服务的独特价值

元服务的呈现形态之一是鸿蒙万能卡片,它是元服务最主要的展示方式之一(其他形态包括语音、图标等)。每一个万能卡片都是一个在桌面上“永远打开的”元服务/应用,以卡片的形式展示元服务/应用的重要信息,并通过轻量级的交互行为实现服务的直达。

元服务带来了体验上的变革,具体表现在以下几个方面:

  1. 免安装:元服务以更轻量化的方式将服务提供给用户,无需进行繁琐的应用安装过程,节省了用户的时间和存储空间。
  2. 一键服务直达:元服务将用户感兴趣的内容前置、外显,通过一键操作即可直接进入所需的服务页面,提供了更快捷、便利的服务体验。
  3. 跨端转移:元服务支持多终端设备间的无缝流转,用户可以在不同的设备上无缝切换使用元服务,提供了更连贯、一致的服务体验。
  4. 情景智能卡片推荐:元服务可以根据用户的需求和偏好进行情景智能卡片推荐,用户可以随心定制自己的服务卡片,并根据个人喜好进行个性化设置,从而更好地满足用户的需求。

通过以上的变革,元服务为用户带来了更轻便、更直观、更智能的服务体验,提升了用户的便利性和满意度。

🔎3.元服务的应用场景

🦋3.1 负一屏

负一屏旨在提供更快速便捷的信息和服务,采用了宫格设计,将常用服务进行分类,涵盖了本地生活、智慧出行、购物娱乐、金融理财等多个场景。用户通过右滑进入发现页,即可轻松地获取所需的服务,无需下载繁琐的App。此外,负一屏还具备实时状态的新体验,用户使用服务后可以随时查看进度,掌握关键节点信息。

🦋3.2 应用市场

打开华为应用市场,点击“应用”页签,进入“元服务”专区发现并使用元服务。

🦋3.3 桌面

用户可以将元服务的卡片添加到桌面,便可在桌面随时随地查看元服务的重要信息,点击卡片即可直达所需服务。

🦋3.4 碰一碰/扫一扫

用户首次“碰一碰”或者“扫一扫”识别设备上的NFC标签,系统引导用户连接设备,连接成功后,再次“碰一碰”或者“扫一扫”即可直接使用相应的元服务。

🚀二、开发环境搭建

🔎1.DevEco Studio

DevEco Studio是一款专门为鸿蒙(HarmonyOS)系统开发而设计的综合性开发工具IDE,开发者可以利用该工具进行鸿蒙应用的设计、开发、调试和发布。DevEco Studio集成了代码编辑器、模拟器、调试工具、图形用户界面设计器和应用管理工具等多个功能,方便开发者进行鸿蒙应用的开发与管理。

DevEco Studio支持多语言开发,包括Java、ArkTS、JavaScript等,同时还支持多种开发模式和框架。此外,它还支持多平台开发,包括手机、平板、智能手表、电视等不同终端设备。

DevEco Studio下载地址:HUAWEI DevEco Studio和SDK下载和升级 | HarmonyOS开发者

安装完成之后界面:

🔎2.配置环境变量

本文以window系统为例,具体操作步骤如下:

1、通过“设置 > 系统 > 系统信息 > 高级系统设置”进入“系统属性”页面的“高级”页签,点击“环境变量”

2、在“系统变量”中添加 HDC_SERVER_PORT和OHOS_HDC_SERVER_PORT 两个变量,变量值设置为未被占用的端口,例如7036和7037

3、在用户或者系统的path变量中,添加HDC工具的路径。
HDC工具路径为:HarmonyOS SDK安装目录/hmscore/{版本号}/toolchains。例如:C:\Users\XXXXX\AppData\Local\Huawei\Sdk\hmscore\3.1.0\toolchains

环境变量配置完成,重启DevEco Studio。

🔎3.诊断开发环境

1、打开项目,从欢迎页进入:底部菜单选择“Help > Diagnose Development Environment”


2、待自动检查完成。如果有检查未通过的项目,请根据检查项的描述和修复建议进行处理

🔎4.下载SDK

1、打开项目,从欢迎页进入:底部菜单选择“Configure > Settings”

🚀三、创建元服务项目

🔎1.创建元服务项目的步骤

1、登录AppGallery Connect, 点击“我的应用”。

首次进入需要签协议


2、在“HarmonyOS”页签,“类型”选择“元服务”,可以查看创建的元服务。

🔎2.选择模板和配置项目属性

1、打开DevEco Studio,菜单选择“File > New > Create Project”,创建一个新工程。

2、选择“Atomic Service”,选择“Empty Ability”模板,点击“Next”。

3、配置工程基本信息。

  • Project name:设置“myProject”。
  • Bundle name:本样例以“com.huawei.myproject”为例。
  • Save location:选择工程存放路径。
  • Compile SDK:支持API 4~9,本样例选择“API 9”。
  • Model:应用支持的模式,API Version 4~8只支持FA模式。
  • Enable Super Visual:是否使用低代码开发模式,本样例不打开此开关。
  • Language:开发语言。
  • Device type:该工程模板支持的设备类型。本样例以手机设备为例。

点击“Finish”,等待工程创建完成,即可进行代码编写。

🔎3.编写代码和调试运行

1、点击右侧的Previewer工具,预览页面效果。

2、新建details.ets页面

details.ets页面

@Entry
@Component
struct Details {build() {//Flex容器组件Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {//Text组件Text('我是跳转页面').fontSize(60).fontWeight(500)}//容器整体宽高.width('100%').height('100%')}
}

main_pages.json页面

{"src": ["pages/Index","pages/details"]
}

3、添加跳转按钮实现页面跳转

index.ets页面

import router from '@ohos.router'
@Entry
@Component
struct Index {@State message: string = '愚公搬代码'build() {//Flex容器组件Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {//Text组件Text('愚公搬代码').fontSize(60).fontWeight(500)//Button组件Button('跳转下一页').fontSize(40).fontWeight(500).width(280).height(60)//点击Button实现页面跳转.onClick(() => {console.info("跳转开始")router.pushUrl({url: 'pages/details' // 目标url}, (err) => {if (err) {console.error(`Invoke pushUrl failed, code is ${err.code}, message is ${err.message}`);return;}console.info('Invoke pushUrl succeeded.');});})}//容器整体宽高.width('100%').height('100%')}
}

🚀四、元服务代码分析

🔎1.元服务代码结构介绍

  • AppScope中存放应用全局所需要的资源文件。
  • entry是应用的主模块,存放HarmonyOS应用的代码、资源等。
  • oh_modules是工程的依赖包,存放工程依赖的源文件。
  • build-profile.json5是工程级配置信息,包括签名、产品配置等。
  • hvigorfile.ts是工程级编译构建任务脚本,hvigor是基于任务管理机制实现的一款全新的自动化构建工具,主要提供任务注册编排,工程模型管理、配置管理等核心能力。
  • oh-package.json5是工程级依赖配置文件,用于记录引入包的配置信息。

🦋1.1 AppScope

  • element文件夹主要存放公共的字符串、布局文件等资源。
  • media存放全局公共的多媒体资源文件。

🦋1.2 entry

  • entryability用于当前ability应用逻辑和生命周期管理。
  • entryformability用于当前卡片生命周期管理。
  • pages存放UI界面相关代码文件,初始会生成一个Index页面。
  • ohosTest是单元测试目录。
  • build-profile.json5是模块级配置信息,包括编译构建配置项。
  • hvigorfile.ts文件是模块级构建脚本。
  • oh-package.json5是模块级依赖配置信息文件。
  • resources目录下存放模块公共的多媒体、字符串及布局文件等资源,分别存放在element、media文件夹中。

🔎2.开发选型

HarmonyOS 3.1及以上版本支持ArkTS、JS语言和Stage模型和FA模型两种模型,其中Stage模型为从HarmonyOS 3.1开始新增的模型,将是长期演进的模型。

HarmonyOS中的Stage模型是指应用程序的窗口管理器和图形引擎。Stage模型包含一个场景(Scene)和多个舞台(Stage),每个舞台表示一个窗口。在舞台上,可以添加多个UI元素(如Button、Label、Image等),通过对UI元素进行布局、组合和交互,实现应用程序的功能。

在HarmonyOS中,通过Stage模型,可以实现窗口管理、多任务处理、图形渲染和事件处理等功能。同时,Stage与HarmonyOS系统的分层架构紧密结合,可以自动适配不同屏幕、不同分辨率的设备,保证应用程序在各种设备上的兼容性和可用性。

一个应用包含一个或者多个Module,以下是Module与UIAbility组件关系示意图:

编译后的示意图:

🔎3.元服务中常用的API和类

  1. OHOS::AAFwk::Ability: 这是Ability的基类,提供了启动、停止和生命周期管理等能力。
  2. OHOS::AAFwk::Want: 跨应用程序组件之间传递的信息,可以指定Intent和Bundle等参数。
  3. OHOS::AppExecFwk::EventHandler: 用于在Ability生命周期内处理异步任务,支持延迟执行和定时执行。
  4. OHOS::EventFwk::EventRunner: 用于实现异步事件的执行和处理。
  5. OHOS::AGP::Window: 应用程序窗口,用于显示UI界面。
  6. OHOS::AGP::View: UI界面中的基本控件,如Button、TextView等。
  7. OHOS::DataAbility::DataAbilityHelper: 数据能力的基础类,用于管理数据的增删改查操作。
  8. OHOS::DistributedSchedule::DistributedSchedulPolicy: 分布式调度策略,用于实现分布式系统的任务调度。
  9. OHOS::Media::MediaPlayer: 用于播放音频和视频文件。
  10. OHOS::Security::Permission: 权限管理类,用于管理应用程序对系统资源的访问权限。

🚀五、案例展示:手语猜一猜

🔎1.案例背景

手语学习元服务的案例背景主要是为了帮助人们学习手语,提高对聋人的理解和尊重。聋人由于听力障碍,无法通过声音语言进行交流,而手语是聋人交流的主要方式。手语学习元服务通过数字化的方式提供了学习手语的机会,让更多的人能够了解手语,学习手语,以便更好地与聋人交流和理解聋人的需求。

随着社会的不断发展,聋人的教育和融入社会的问题日益重要。手语学习应用可以提供数字化的手语课程,让更多的人能够学习手语,提高对聋人的理解和尊重,促进聋人的教育和融入社会。

手语是一种非常有意义的语言,它不仅可以让聋人与人进行有效的交流,还可以帮助听力正常的人了解和尊重聋人的文化和生活习惯。手语学习应用也可以成为一个重要的手语文化传播平台,让更多的人了解和学习手语,促进手语文化的传播和发展。

🔎2.功能简介

元服务:
1、提供专业手语翻译老师示范视频,包括基本手势、字母表、常用短语等。用户可以点击观看示范并模仿。
2、提供类似答题模块,帮助用户巩固所学的手语知识,用户可以完成答题模块测试自己的进步。

元服务卡片:
1、卡片界面展示每日一题,并可以在卡片上进行答题学习

🔎3.案例实现流程

🦋3.1 内部应用功能

☀️3.1.1 首页功能

首页功能主要包含了4块功能:每日挑战、课程、测试、学习记录

🌈3.1.1.1 每日挑战

每日挑战主要的交互有2块功能:换一换和答题

换一换:主要实现题目和资源的切换(替换题目、替换视频链接)

答题:主要是根据选项遍历出Button按钮,在根据按钮点击事件判断点击的按钮type等于1则答题正确

源码片段如下:

Flex({ justifyContent: FlexAlign.SpaceBetween }){Text('每日挑战').fontSize(20).fontColor('#fff').width('50%')Column() {Flex({ justifyContent: FlexAlign.End  }) {Image(this.ic_new).width(20).height(20).margin({right:5})Text('换一批').fontSize(20).fontColor('#fff').onClick(()=>{this.anyArray=[{name:'吃',type:1},{name:'厲害',type:0}]this.videoSrc=$rawfile('quick.mp4')this.previewUri=$r('app.media.quick')})}.width('50%')}
}.padding(10).backgroundColor('#938cf4')Column(){Column(){Flex({justifyContent:FlexAlign.SpaceBetween}){Text('根据视频所示,选择正确的答案').fontSize(12).fontColor('#fff')Text('40%的人答错').fontSize(12).fontColor('#fff')}.padding({top:10,left:10,right:10,bottom:10}).margin({top:0})Video({src: this.videoSrc,previewUri: this.previewUri,currentProgressRate: this.curRate,controller: this.controller}).width('100%').height(180).padding(5).borderRadius(1).margin({top:0,left:10,right:10,bottom:10,})Flex({justifyContent:FlexAlign.SpaceBetween}){ForEach(this.anyArray,(item)=>{Button(item.name,{ type: ButtonType.Normal,}).borderRadius(0).width('45%').backgroundColor('#ff986ec8').onClick(()=>{if(item.type==1){if (this.dialogController != undefined) {this.dialogController.open()this.textValue='答对了'}}else{if (this.dialogController != undefined) {this.dialogController.open()this.textValue='答错了'}}})})}.margin({top:0,left:10,right:10,bottom:10,})}.backgroundColor('#ffa49fea').margin({top:0,left:10,right:10,bottom:10,}).borderRadius(10)}.backgroundColor('#938cf4')
🌈3.1.1.2 课程

这边主要是点击按钮跳转到课程页面一个功能

源码片段如下:

Column() {Flex({ alignItems: this.alignItems }) {Text('课程').width('50%').fontSize(20).fontWeight(FontWeight.Bold)}.size({width: '90%',}).padding({top:20,left:10,bottom:0})Flex({ justifyContent: FlexAlign.SpaceBetween }) {Text('初级课程,易上手').width('70%').fontSize(16).fontWeight(FontWeight.Bold).fontColor('#c4c2cf')Button('学习').width('30%').backgroundColor('#fecc5b').margin({top:-25,}).onClick(()=>{router.push({ url: 'pages/list' })})}.size({width: '100%', }).padding({ left: 30 ,top:10,right:30,bottom:20},).border({radius:{bottomLeft: 15, bottomRight: 15}})
}.width('90%')
.backgroundColor('#fff')
.borderRadius(15)
.margin(20)
🌈3.1.1.3 测试

这边主要是点击按钮跳转到测试页面一个功能

源码片段如下:

Column() {Flex({ alignItems: this.alignItems }) {Text('课程').width('50%').fontSize(20).fontWeight(FontWeight.Bold)}.size({width: '90%',}).padding({top:20,left:10,bottom:0})Flex({ justifyContent: FlexAlign.SpaceBetween }) {Text('初级课程,易上手').width('70%').fontSize(16).fontWeight(FontWeight.Bold).fontColor('#c4c2cf')Button('学习').width('30%').backgroundColor('#fecc5b').margin({top:-25,}).onClick(()=>{router.push({ url: 'pages/list' })})}.size({width: '100%', }).padding({ left: 30 ,top:10,right:30,bottom:20},).border({radius:{bottomLeft: 15, bottomRight: 15}})
}.width('90%')
.backgroundColor('#fff')
.borderRadius(15)
.margin(20)
🌈3.1.1.4 学习记录

这边主要是基于组件的形式在界面展示,功能点主要有:时间数据、学习课程数

  • 时间数据:已当前时间自动更新
  • 学习课程数:来源于已学课程的本地存储数据(存储来源在课程学习界面)

源码片段如下:

PersistentStorage.PersistProp('course', 0);let date = new Date()
let time = date.getFullYear() + "年" + (date.getMonth() + 1) + "月" + date.getDate() + "日"
console.log(time);
@Component
export default struct studyCollect {alignItems : number = 0// @State timeDate:string = date@StorageLink('course') course: number = 0@State dayTime:string=time;build() {Column() {Flex({ alignItems: this.alignItems }) {Text('学习记录').width('50%').fontSize(20).fontWeight(FontWeight.Bold)Text(` ${this.dayTime}`).width('50%').height(30).textAlign(TextAlign.End)}.size({width: '90%', height: 50}).margin({top:10}).padding(10)Flex({ alignItems: this.alignItems }) {Text(`已学${this.course}课程`).width('50%').height(20).fontSize(16).fontWeight(FontWeight.Bold).fontColor('#fff')Text(`${this.course}分钟`).width('50%').height(20).textAlign(TextAlign.End).fontColor('#fff')}.size({width: '100%', height: 50}).padding({ left: 40 ,top:15,right:40,},).border({radius:{bottomLeft: 15, bottomRight: 15}}).backgroundColor('#938cf4')}.width('90%').backgroundColor('#fff').borderRadius(15).margin({top:5})}
}
☀️3.1.2 课程功能

课程主页面主要是课程信息展示和跳转到具体详情页面

源码片段如下:

import router from '@ohos.router';import { arrImage } from '../common/json'
@Entry
@Component
struct list {scroller: Scroller = new Scroller();@State arrImage: Object[]=arrImagebuild() {Scroll(this.scroller) {Column() {Column({ space: 5 }) {Text('初级课程').fontSize(20).fontColor('#fff').width('90%').padding(10).backgroundColor('')Flex({ wrap: FlexWrap.Wrap, justifyContent: FlexAlign.SpaceBetween }) {ForEach(this.arrImage, (item) => {Column() {Image(item.image).width('100%').height(120)Text(item.name).lineHeight(30)}.width('45%').height(150).backgroundColor(0xF5DEB3).margin(5).onClick(()=>{router.pushUrl({url:'pages/details',params:{text:item.name,image:item.image,video:item.video}})})})}.width('100%').padding(10).backgroundColor(0xAFEEEE)}.width('100%').margin({ top: 5 })}.width('100%').backgroundColor('#938cf4')}.backgroundColor(0xDCDCDC).scrollable(ScrollDirection.Vertical) // 滚动方向纵向.scrollBar(BarState.On) // 滚动条常驻显示.scrollBarColor(Color.Gray) // 滚动条颜色.scrollBarWidth(5) // 滚动条宽度.edgeEffect(EdgeEffect.Spring) // 滚动到边沿后回弹}
}
🌈3.1.2.1 课程详情页

功能点主要有:路由数据、客户对课程的状态信息

  • 路由数据:手语答案、手语视频地址
  • 客户对课程的状态信息:点赞、收藏、转发相关状态变更

源码片段如下:

import router from '@ohos.router'
import promptAction from '@ohos.promptAction'import { CommonTitleBar } from '../common/CommonTitleBar';@Entry
@Component
struct Index {@StorageLink('course') course: number = 0// @State good:Resource=$r('app.media.icon_good');@State goodStatus:boolean=true@State goodNumber:number=0@State startStatus:boolean=true@State startNumber:number=0@State shareStatus:boolean=true@State shareNumber:number=0@State text: string = router.getParams()['text']@State previewUri: Resource = router.getParams()['image']@State videoSrc: Resource = router.getParams()['video']@State curRate: PlaybackSpeed = PlaybackSpeed.Speed_Forward_1_00_Xcontroller: VideoController = new VideoController()alignItems : number = 0build() {Column(){// CommonTitleBar({attribute: {//   bg_color: '#ff2ad4b2',//   close_text: '返回',//   closeCallback: () => {////   },//   title_text: '标题',//   menuCallback: () => {////   }// }})Column(){Column(){Video({src: this.videoSrc,previewUri: this.previewUri,currentProgressRate: this.curRate,controller: this.controller}).width('100%').height(180).padding(10).borderRadius(10).onFinish(() => {this.course += 1;console.info('onFinish')})}Flex(){Text('当前示例:').fontSize(24)Text(`${this.text}`).fontSize(24)}.padding(10)Flex({}){Flex(){Image(this.goodStatus ? $r("app.media.icon_good"):$r("app.media.active_icon_good")).width(24).height(24)Text(`${this.goodNumber}`).height(25)}.width('20%').onClick(()=>{this.goodStatus=!this.goodStatus;this.goodStatus ? this.goodNumber--:this.goodNumber++;promptAction.showToast({message: this.goodStatus ? '取消点赞' :'点赞成功',duration: 2000,});})Flex(){Image(this.startStatus ? $r("app.media.icon_star"):$r("app.media.active_icon_star")).width(24).height(24)Text(`${this.startNumber}`).height(25)}.width('20%').onClick(()=>{this.startStatus=!this.startStatus;this.startStatus ? this.startNumber--:this.startNumber++;promptAction.showToast({message: this.startStatus ? '取消收藏' :'收藏成功',duration: 2000,});})Flex(){Image(this.shareStatus ? $r("app.media.icon_share"):$r("app.media.active_icon_share")).width(24).height(24)Text(`${this.shareNumber}`).height(25)}.width('20%').onClick(()=>{this.shareStatus=!this.shareStatus;this.shareStatus ? this.shareNumber--:this.shareNumber++;promptAction.showToast({message: this.shareStatus ? '取消转发' :'转发成功',duration: 2000,});})}.padding(10)}}//容器整体宽高.width('100%').height('100%').backgroundColor('#ff0f2ff')}
}
☀️3.1.3 测试功能

测试功能页面主要功能是从json的题库取出10题,如果答题正确会自动切换到下一题。

源码片段如下:

import router from '@ohos.router'import promptAction from '@ohos.promptAction'
import { arrImage } from '../common/json'
@Entry
@Component
struct Index {@State onActive : number = 1@State arrImage: Object[]=arrImage@State videoSrc: Resource = $rawfile('hello.mp4')@State previewUri: Resource = $r("app.media.hello")@State curRate: PlaybackSpeed = PlaybackSpeed.Speed_Forward_1_00_Xcontroller: VideoController = new VideoController()alignItems : number = 0@State message: string = '手语猜猜看'@State studyName: string = '手语阅览'@State collectName: string = '手语挑战'@State testName: string = '测试'@State arr: string[] =['你好','出生','爱','晚饭','中午','明天']build() {Column(){Column(){Flex({alignItems:ItemAlign.Center,justifyContent:FlexAlign.Center}){// Text(`${this.arrImage[this.onActive]['name']}`)Text(`${this.onActive}`).fontSize(28)Text('/').fontSize(28)Text(`${this.arrImage.length}`).fontSize(28)}.margin(10)Column(){Video({src: this.arrImage[this.onActive-1]['video'],previewUri: this.arrImage[this.onActive-1]['image'],currentProgressRate: this.curRate,controller: this.controller}).width('100%').height(180).margin({top:0,bottom:0,})}Column({}){Text('在下列选项中选择正确答案?').width('100%').padding(10).fontSize(20)}.backgroundColor('#fff')Flex({wrap: FlexWrap.Wrap }){ForEach(this.arrImage[this.onActive-1]['answer'],(item:string)=>{Button(item,{ type: ButtonType.Normal,}).margin(5).borderRadius(5).onClick(() => {console.log(item)if(this.onActive>=this.arrImage.length){promptAction.showToast({message: '闯关已结束',duration: 2000,});router.back({url:'pages/index'});return false;}if(item==this.arrImage[this.onActive-1]['name']){promptAction.showToast({message: '答对了,请继续下一题',duration: 2000,});this.onActive=this.onActive+1;}else{promptAction.showToast({message: '答错了',duration: 2000,});}})})}.padding(10)}}//容器整体宽高.width('100%').height('100%').backgroundColor('#ff0f2ff')}
}

🦋3.2 卡片功能

这边和每日挑战功能类似,主要多了些动画效果,卡片主要的交互有2块功能:换一换和答题

  • 换一换:主要实现题目和资源的切换(替换题目、替换视频链接)
  • 答题:主要是根据选项遍历出Button按钮,在根据按钮点击事件判断点击的按钮type等于1则答题正确

源码片段如下:

@Entry
@Component
struct WidgetCard {@State onActive:number=0@State arrImage: Object[] = [{name:'你好',image:$r("app.media.hello"),content:'一手食指指向对方。一手握拳,向上伸出拇指。',video:$rawfile('hello.mp4'),anyArray:[{name:'你好',type:1},{name:'谢谢',type:0}]},{name:'谢谢',image:$r('app.media.thank'),content:'一手伸出拇指,弯曲两下,表示向人感谢。',video:$rawfile('thank.mp4'),anyArray:[{name:'不好',type:0},{name:'谢谢',type:1}]},{name:'爱',image:$r('app.media.love'),content:'一手轻轻抚摩另一手拇指指背,表示一种“怜爱”的感情',video:$rawfile('love.mp4'),anyArray:[{name:'没有',type:0},{name:'爱',type:1}]},{name:'喜欢',image:$r('app.media.live'),video:$rawfile('like.mp4'),content:'一手拇、食指微曲,指尖抵于颌下,头微微点动一下。	',anyArray:[{name:'没有',type:0},{name:'喜欢',type:1}]},{name:'不喜欢',image:$r('app.media.dislike'),video:$rawfile('dislike.mp4'),content:'一手伸直,左右摆动几下。	一手拇、食指微曲,指尖抵于颌下,头微微点动一下。	',anyArray:[{name:'好晕',type:0},{name:'不喜欢',type:1}]},{name:'饭',image:$r('app.media.eat'),video:$rawfile('eat.mp4'),content:'(一)一手拇、食指相对,中间留有米粒大小距离。(二)一手伸食、中指象征筷子,作吃饭动作。',anyArray:[{name:'可爱',type:0},{name:'饭',type:1}]},{name:'快',image:$r('app.media.quick'),video:$rawfile('quick.mp4'),content:'一手拇、食指相捏,很快地从一侧向另一侧作快速挥动,象征物体运动速度很快。',anyArray:[{name:'慢',type:0},{name:'快',type:1}]},{name:'慢',image:$r('app.media.slow'),video:$rawfile('show.mp4'),content:'一手掌心向下,慢慢地上下微动几下,象征物体运动速度缓慢。',anyArray:[{name:'去',type:0},{name:'慢',type:1}]},{name:'没关系',image:$r('app.media.matter'),video:$rawfile('matter.mp4'),content:'一手拇、食、中指捻动,连续几次。	两手拇、食指搭成圆圈,互相套环。	',anyArray:[{name:'人类',type:0},{name:'没关系',type:1}]},{name:'厉害',image:$r('app.media.powerful'),video:$rawfile('powerful.mp4'),content:'一手打手指字母“L”的指式,并绕脸部转一圈。同时面部作出严厉的表情。	',anyArray:[{name:'好帅',type:0},{name:'厉害',type:1}]},];/** The max lines.*/readonly MAX_LINES: number = 1;/** The action type.*/readonly ACTION_TYPE: string = 'router';/** The message.*/readonly MESSAGE: string = 'add detail';/** The ability name.*/readonly ABILITY_NAME: string = 'EntryAbility';/** The with percentage setting.*/readonly FULL_WIDTH_PERCENT: string = '100%';/** The height percentage setting.*/readonly FULL_HEIGHT_PERCENT: string = '100%';@State opacityAngle: number =  0.8@State mainFlag: boolean = false;@State flag: boolean = true;build() {Stack() {if(this.flag){Image(this.arrImage[this.onActive]['image']).width(this.FULL_WIDTH_PERCENT).height(this.FULL_HEIGHT_PERCENT).objectFit(ImageFit.Cover).opacity(this.opacityAngle).transition({ type: TransitionType.Insert, translate: { x: 0, y: 0 } }).transition({ type: TransitionType.Delete, opacity: 0, scale: { x: 0, y: 0 } })}else{Image(this.arrImage[this.onActive]['image']).width(this.FULL_WIDTH_PERCENT).height(this.FULL_HEIGHT_PERCENT).objectFit(ImageFit.Cover).opacity(this.opacityAngle).transition({ type: TransitionType.Insert, translate: { x: 0, y: 0 } }).transition({ type: TransitionType.Delete, opacity: 0, scale: { x: 0, y: 0 } })}Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.Center }){Image($r("app.media.ic_new")).width(11).height(11).margin({left:10,top:3,right:5})Text("换一批").fontSize('8fp').width(40).fontColor('#fff').margin({top:3})}.backgroundColor('#fecc5b').width(50).height(15).borderRadius(10).onClick(()=>{animateTo({ duration: 1000 }, () => {this.flag = !this.flag;this.onActive=(this.onActive+1)%this.arrImage.length;})}).position({ x: 10, y: 10 })Column(){Flex({justifyContent:FlexAlign.SpaceBetween}){ForEach(this.arrImage[this.onActive]['anyArray'],(item)=>{Button(item.name,{ type: ButtonType.Normal,}).fontSize('8fp').borderRadius(10).height(20).width('45%').backgroundColor('#fecc5b').onClick(()=>{console.log('44')if(item.type==1){animateTo({ duration: 1000 }, () => {this.flag = !this.flag;this.onActive=(this.onActive+1)%this.arrImage.length;})}else{}})})}}.margin({top:110,left:10,right:10})Text(this.arrImage[this.onActive]['content']).fontSize('7fp').opacity($r('app.float.detail_immersive_opacity')).margin({ top: '70vp',left:'10vp',right:'10vp' }).textOverflow({ overflow: TextOverflow.Ellipsis }).fontColor('#000').fontWeight('900').maxLines(this.MAX_LINES)}.width(this.FULL_WIDTH_PERCENT).height(this.FULL_HEIGHT_PERCENT).onClick(() => {postCardAction(this, {"action": this.ACTION_TYPE,"abilityName": this.ABILITY_NAME,"params": {"message": this.MESSAGE}});})}
}

元服务项目源码:https://download.csdn.net/download/aa2528877987/88484307

🚀总结

手语猜一猜元服务的实现借助了HarmonyOS的跨应用数据共享和功能交互特性,让用户可以通过手势输入手语,并进行识别和猜词游戏。这种应用方式不仅提供了娱乐和互动的体验,还促进了手语的学习和交流。通过使用该应用,我深刻体会到了HarmonyOS元服务的便利和灵活性。

开发使用HarmonyOS元服务可以带来许多好处,包括跨设备互联、数据共享和交互、灵活性和扩展性,以及性能优化。我鼓励大家积极尝试使用HarmonyOS元服务,开发出更好属于自己的应用。

🚀附录

  • 元服务介绍:元服务-元服务万能卡片-元服务开发解决方案-华为开发者联盟
  • ArkTS语言介绍: ArkTS 语言 - HarmonyOS应用开发官网
  • 端云一体化开发介绍:文档中心
  • 低代码开发介绍:文档中心

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/162173.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

什么是高防IP?有什么优势?怎么选择高防IP?

在当今的互联网环境中,分布式拒绝服务(DDoS)攻击已经成为一种常见的安全威胁。这种攻击通过向目标服务器发送大量的无效流量,使其无法处理正常的请求,从而达到迫使服务中断的目的。作为一个用户,你是否曾遇…

QGIS文章五——对遥感影像进行土地类型分类—监督分类(dzetsaka : classification tool)...

dzetsaka classification tool是QGIS的强大分类插件,目前主要提供了高斯混合模型分类器、Random Forest、KNN和SVM四种分类器模型,相比于SCP(Semi-Automatic Classification),他的一个特点就是功能专一,操作简单。 从十一月开始一…

Linux基础命令3

移动,剪切文件 普通文件的移动剪切 现在在这儿 上图中,mv y.x ./tmp的意思,就是将当前路径下的y.x文件进行剪切,然后放到路径为当前路径下的tmp目录文件夹里面 操作完成后可以cd tmp,ls看到y.x文件已经在里面了 现在…

京东内部员工,爆料工资与公积金收入!

精彩回顾:进了央企,拿了户口,却感觉被困住了。 每个企业都有它的一套规则,哪些人适合加薪,哪些人适合拿奖金,哪些人适合给股票期权等等。但是说实话,很多人都只能拿底薪,这些福利啥的…

数据挖掘 K近邻

什么时候用K近邻? 交叉验证的时候。最常见的交叉验证方法是K折交叉验证,其中数据集被均匀分成K个子集,称为折,然后执行K次训练和测试,每次选择不同的折作为测试集,其余的作为训练集。最后,将K次…

JavaScript编程基础 – 对象

JavaScript编程基础 – 对象 JavaScript Programming Essentials – Object 本文简要介绍JavaScript面向对象编程,如何实现其中的对象以及实例演示,希望对大家学习JavaScript有所帮助。 1. 面向对象编程特点 面向对象编程(Object-Oriented Programmi…

浅谈JDK动态代理(上)

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO 联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬 到目前为止&#xff0c…

力扣OJ题讲解——循环队列

今天我们一起来做一道关于队列的OJ题目,这是力扣题目622题,点击题目链接可以直接跳转,https://leetcode.cn/problems/design-circular-queue/ 首先,我们看到要求,需要我们实现哪些功能? 我们需要设置队列长…

经典双指针算法试题(二)

📘北尘_:个人主页 🌎个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上,不忘来时的初心 文章目录 一、有效三角形的个数1、题目讲解2、讲解算法原理3、代码实现 二、查找总价格为目标值的两个商…

Hutool

一、简介 Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅 官方文档: https://www.hutool.cn/docs/#/ 二、包含组件 一个Java基础工具类,对文…

allegro画封装时使用坐标指令无效

使用坐标指令时显示:“Pick is outside the extent of the drawing…pick again” 这是因为你放的引脚已经超出你这个绘制界面的定义尺寸,需要到Setup->Design pararmeters…里面去将图幅改大一点,如下图所示: 然后点击Design…

消息中间件——RabbitMQ(三)理解RabbitMQ核心概念和AMQP协议!

前言 本章学习,我们可以了解到以下知识点: 互联网大厂为什么选择RabbitMQ?RabbiMQ的高性能之道是如何做到的?什么是AMQP高级协议?AMQP核心概念是什么?RabbitMQ整体架构模型是什么样子的?Rabbi…

P8599 [蓝桥杯 2013 省 B] 带分数(dfs+全排列+断点判断)

思路&#xff1a;1.深度枚举所有排列情况 2.设置为每个排列设置两个断点&#xff0c;分为三部分&#xff1a;a,b,c 3.转换为乘法判断条件&#xff0c;满足加一 代码如下&#xff1a;&#xff08;可用next_permutation全排列函数代替dfs&#xff09; #include<iostream>…

全面的日志监控管理工具

企业网络由众多日志源组成。集中监控这些日志源有助于防止数据威胁和网络攻击&#xff0c;综合日志监控解决方案可以自动执行日志管理流程&#xff0c;通过关联日志来识别恶意活动&#xff0c;并帮助满足IT合规性要求。 不同类型的日志监控 EventLog Analyzer 综合日志监控解…

智慧法院档案数字化解决方案

智慧法院档案数字化解决方案可以采用以下步骤&#xff1a; 1. 确定数字化目标&#xff1a;明确数字化的目标和范围&#xff0c;比如将所有的案件相关文件、纸质档案和材料进行数字化。 2. 确定数字化流程&#xff1a;制定数字化的流程和标准&#xff0c;比如采用哪些设备和软件…

【C语言】qsort函数

目录 简介 头文件 ​编辑 函数原型&#xff1a; 参数函数如何写&#xff1a; 参数函数要求&#xff1a; qsort对整性数据的排序&#xff1a; qsort对字符型数据的排序&#xff1a; 对结构体类型的内部元素排序&#xff1a; 函数的底层是以快速排序实现的 但是本文不深入…

小黑子—Maven高级

Maven高级篇 二 小黑子的Maven高级篇学习1. 分模块开发1.1 分模块开发设计1.2 分模块开发实现1.2.1 抽取domain层1.2.2 抽取dao层 2. 依赖管理2.1 依赖传递2.2 可选依赖2.3 排除依赖 3. 继承与聚合3.1 聚合3.2 继承3.3 总结 4. 属性4.1 配置文件加载属性4.2 版本管理 5. 多环境…

【开源】基于Vue.js的民宿预定管理系统

项目编号&#xff1a; S 058 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S058&#xff0c;文末获取源码。} 项目编号&#xff1a;S058&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 用例设计2.2 功能设计2.2.1 租客角色…

梦开始的地方——Adobe Premiere Pro

今天&#xff0c;我们来说说一款老生常谈的相信也是很多人都经常迫切需要的软件。Adobe Premiere Pro&#xff0c;简称Pr&#xff0c;是由Adobe公司开发的一款视频编辑软件。 Premiere Pro是视频编辑爱好者和专业人士必不可少的视频编辑工具。它可以提升您的创作能力和创作自由…

httpd(Web服务器)

名词解释 1、URL&#xff1a;Uniform Resource Locator&#xff0c;统⼀资源定位符 2、⽹址格式&#xff1a;<协议>://<主机或主机名>[:port]/<⽬录资源,路径> 3、主机地址/主机名&#xff1a;主机地址是服务器在因特⽹所在的IP地址。主机名就需要域名解析…