鸿蒙NEXT开发案例:九宫格随机
【引言】
在鸿蒙NEXT开发中,九宫格抽奖是一个常见且有趣的应用场景。通过九宫格抽奖,用户可以随机获得不同奖品,增加互动性和趣味性。本文将介绍如何使用鸿蒙开发框架实现九宫格抽奖功能,并通过代码解析展示实现细节。
【环境准备】
• 操作系统:Windows 10
• 开发工具:DevEco Studio NEXT Beta1 Build Version: 5.0.3.806
• 目标设备:华为Mate60 Pro
• 开发语言:ArkTS
• 框架:ArkUI
• API版本:API 12
【思路】
本案例中的“九宫格随机”应用旨在模拟一个简单的抽奖场景,用户点击抽奖按钮后,程序会从预先定义好的九个奖品中随机选择一个作为最终奖品。整个应用采用了响应式编程模式,结合鸿蒙NEXT提供的组件化开发方式,实现了交互流畅、视觉效果良好的用户体验。
1. Prize类设计 应用首先定义了一个Prize类,用于表示奖品信息。该类使用了@ObservedV2装饰器,使得奖品属性(如标题、颜色、描述)的变化可以被自动追踪,从而实现UI的实时更新。构造函数允许创建具有特定属性值的奖品实例,便于后续管理。
2. MyPrizeUpdate结构组件 为了提供奖品信息的编辑功能,我们创建了MyPrizeUpdate结构组件。它通过接收外部传入的数据(当前选中的奖品索引、抽奖顺序数组及所有奖品的数组),构建了一个包含文本输入框的界面,用户可以在其中修改奖品的标题、描述和颜色。任何对这些属性的更改都会即时反映到对应的奖品对象上,并触发UI的相应更新。
3. LotteryPage入口组件LotteryPage是整个抽奖应用的核心组件,负责组织页面布局和处理用户交互逻辑。它初始化了一系列必要的状态变量,比如保存所有奖品的数组prizeArray、定义抽奖顺序的selectionOrder以及控制动画状态的isAnimating等。此外,该组件实现了抽奖过程的关键方法——startLottery(开始抽奖)、runAtConstantSpeed(匀速运行)和slowDown(减速),它们共同协作以模拟真实的抽奖体验。当用户点击抽奖按钮时,这些方法按照预定的速度模式依次调用,直到最终确定一个奖品为止。最后,通过弹出对话框的方式向用户展示抽奖结果。
4. UI布局与样式 在构建UI方面,应用充分利用了鸿蒙NEXT提供的布局容器(如Column、Row、Flex)和样式属性(如宽度、高度、边距、背景色、圆角、阴影),精心设计了每个奖品项的外观。特别地,对于抽奖按钮,不仅设置了独特的背景颜色,还在点击事件中添加了动画效果,增强了用户的参与感。同时,考虑到不同设备屏幕尺寸的差异,所有布局元素均采用相对单位进行设置,确保了应用在各种终端上的良好适配性。
5. 动画与交互优化 为了让抽奖过程看起来更加生动有趣,应用引入了加速、匀速、减速三个阶段的动画效果,使选中的奖品项能够以逐渐加快然后缓慢停止的方式出现在用户面前。这种变化不仅增加了悬念感,也提升了整体的娱乐性。此外,通过对点击事件的监听和处理,确保了即使是在动画过程中,用户的交互也不会受到影响,保证了良好的用户体验。
【完整代码】
// 定义一个可观察的Prize类,用于表示奖品信息。
@ObservedV2
class Prize {@Trace title: string // 奖品标题属性,使用@Trace进行追踪以便响应式更新UI@Trace color: string // 奖品颜色属性@Trace description: string // 奖品描述属性// 构造函数,用来初始化新的奖品实例constructor(title: string, color: string, description: string = "") {this.title = title // 设置奖品标题this.color = color // 设置奖品颜色this.description = description // 设置奖品描述,默认为空字符串}
}// 定义MyPrizeUpdate结构组件,用于显示和编辑选中的奖品信息
@Component
struct MyPrizeUpdate {@Consume selectedIndex: number // 当前选中的奖品索引@Consume private selectionOrder: number[] // 保存抽奖顺序的数组@Consume private prizeArray: Prize[] // 保存所有奖品的数组build() {Column({ space: 20 }) { // 创建列布局容器,设置子元素之间的间距为20pxRow() { // 创建行布局容器Text('标题:') // 显示“标题”文本TextInput({ text: this.prizeArray[this.selectionOrder[this.selectedIndex%this.selectionOrder.length]].title }).width('300lpx') // 设置输入框宽度.onChange((value) => { // 监听输入框内容变化this.prizeArray[this.selectionOrder[this.selectedIndex%this.selectionOrder.length]].title = value // 更新奖品标题})}Row() {Text('描述:')TextInput({text: `${this.prizeArray[this.selectionOrder[this.selectedIndex%this.selectionOrder.length]].description}`}).width('300lpx').onChange((value) => { // 同上,但针对奖品描述this.prizeArray[this.selectionOrder[this.selectedIndex%this.selectionOrder.length]].description = value})}Row() {Text('颜色:')TextInput({text: `${this.prizeArray[this.selectionOrder[this.selectedIndex%this.selectionOrder.length]].color}`}).width('300lpx').onChange((value) => { // 同上,但针对奖品颜色this.prizeArray[this.selectionOrder[this.selectedIndex%this.selectionOrder.length]].color = value})}}.justifyContent(FlexAlign.Start) // 设置内容左对齐.padding(40) // 设置内边距.width('100%') // 设置宽度为100%.backgroundColor(Color.White) // 设置背景颜色为白色}
}// 定义抽奖页面入口组件
@Entry
@Component
struct LotteryPage {@Provide private selectedIndex: number = 0 // 提供当前选中的索引,初始值为0private isAnimating: boolean = false // 标记是否正在进行动画,初始值为false@Provide private selectionOrder: number[] = [0, 1, 2, 5, 8, 7, 6, 3] // 定义抽奖顺序private cellWidth: number = 200 // 单元格宽度private baseMargin: number = 10 // 单元格边距@Provide private prizeArray: Prize[] = [new Prize("红包", "#ff9675", "10元"), // 初始化奖品数组,创建各种奖品对象new Prize("话费", "#ff9f2e", "5元"),new Prize("红包", "#8e7fff", "50元"),new Prize("红包", "#48d1ea", "30元"),new Prize("开始抽奖", "#fffdfd"), // 抽奖按钮,没有具体奖品描述new Prize("谢谢参与", "#5f5f5f"),new Prize("谢谢参与", "#5f5f5f"),new Prize("超市红包", "#5f5f5f", "100元"),new Prize("鲜花", "#75b0fe"),]private intervalID: number = 0 // 定时器ID,用于控制抽奖速度@State isSheetVisible: boolean = false // 控制底部弹出表单的可见性// 开始抽奖逻辑startLottery(speed: number = 500) {setTimeout(() => { // 设置延时执行if (speed > 50) { // 如果速度大于50,则递归调用startLottery以逐渐加速speed -= 50this.startLottery(speed)} else {this.runAtConstantSpeed() // 达到最高速度后进入匀速阶段return}this.selectedIndex++ // 每次调用时更新选中索引}, speed)}// 以恒定速度运行抽奖runAtConstantSpeed() {let speed = 40 + Math.floor(Math.random() * this.selectionOrder.length) // 随机生成一个速度值clearInterval(this.intervalID) // 清除之前的定时器this.intervalID = setInterval(() => { // 设置新的定时器来更新选中索引if (this.selectedIndex >= speed) { // 如果选中索引达到速度值,停止并进入减速阶段clearInterval(this.intervalID)this.slowDown()return}this.selectedIndex++}, 50)}// 减速逻辑slowDown(speed = 50) {setTimeout(() => { // 设置延时执行if (speed < 500) { // 如果速度小于500,则递归调用slowDown以逐渐减速speed += 50this.slowDown(speed)} else {this.selectedIndex %= this.selectionOrder.length // 确保索引在有效范围内let index = this.selectionOrder[this.selectedIndex] // 获取最终选中的奖品索引this.isAnimating = false // 动画结束this.getUIContext().showAlertDialog({ // 显示结果对话框title: '结果',message: `${this.prizeArray[index].title}${this.prizeArray[index].description}`, // 显示奖品信息confirm: {defaultFocus: true,value: '我知道了', // 确认按钮文本action: () => {} // 点击确认后的操作},alignment: DialogAlignment.Center,});return}this.selectedIndex++}, speed)}// 构建UI方法build() {Column() { // 使用Column布局容器Flex({ wrap: FlexWrap.Wrap }) { // 使用弹性布局,允许换行ForEach(this.prizeArray, (item: Prize, index: number) => { // 遍历奖品数组,创建每个奖品的UIColumn() { // 使用Column布局容器为每个奖品项Text(`${item.title}`) // 显示奖品标题.fontColor(index == 4 ? Color.White : item.color) // 设置字体颜色,对于抽奖按钮特殊处理.fontSize(16)Text(`${item.description}`) // 显示奖品描述.fontColor(index == 4 ? Color.White : item.color) // 设置字体颜色.fontSize(20)}.clickEffect({ level: ClickEffectLevel.LIGHT, scale: 0.8 }) // 添加点击效果.onClick(() => { // 处理点击事件if (this.isAnimating) { // 如果正在动画中,忽略点击return}if (index == 4) { // 如果点击的是抽奖按钮,开始抽奖this.isAnimating = truethis.startLottery()} else {for (let i = 0; i < this.selectionOrder.length; i++) {if (this.selectionOrder[i] == index) {this.selectedIndex = i // 更新选中索引到对应位置}}}}).alignItems(HorizontalAlign.Center) // 设置水平居中对齐.justifyContent(FlexAlign.Center) // 设置垂直居中对齐.width(`${this.cellWidth}lpx`) // 设置单元格宽度.height(`${this.cellWidth}lpx`) // 设置单元格高度.margin(`${this.baseMargin}lpx`) // 设置单元格边距.backgroundColor(index == 4 ? "#ff5444" : // 抽奖按钮背景颜色特殊处理(this.selectionOrder[this.selectedIndex % this.selectionOrder.length] == index ? Color.Gray : Color.White)).borderRadius(10) // 设置圆角.shadow({ // 设置阴影效果radius: 10,color: "#f98732",offsetX: 0,offsetY: 20})})}.width(`${this.cellWidth * 3 + this.baseMargin * 6}lpx`) // 设置整体宽度.margin({ top: 30 }) // 设置顶部边距MyPrizeUpdate().margin({top:20}) // 插入MyPrizeUpdate组件,并设置其上边距}.height('100%') // 设置高度为100%.width('100%') // 设置宽度为100%.backgroundColor("#ffb350") // 设置页面背景颜色}
}
相关文章:

鸿蒙NEXT开发案例:九宫格随机
【引言】 在鸿蒙NEXT开发中,九宫格抽奖是一个常见且有趣的应用场景。通过九宫格抽奖,用户可以随机获得不同奖品,增加互动性和趣味性。本文将介绍如何使用鸿蒙开发框架实现九宫格抽奖功能,并通过代码解析展示实现细节。 【环境准…...

深度解析:RTC电路上的32.768KHz时钟的频偏及测试
1、什么是RTC RTC是Real-Time Clock(实时时钟)的缩写,通常在电子产品中,是用时钟电路(外部采用时钟芯片,比如AiP8563)或时钟模块(SOC内部包含了时钟模块,只需要外接32.768KHz晶振)来…...
Scala的泛型
需求:定义一个名为getMiddleEle 的方法用它来获取当前的列表的中间位置的值中间位置的下标 长度/2目标:getMiddleEle(List(1,2,3,4,5)) > 5/2 2 > 下标为2的元素是:3 getMiddleEle(List(1,2,3,4)) > 4/2 2 > 下标为2的元素是:3格式如下: 定义一个函数的格式:def…...
OpenGL ES详解——glUniform1i方法是否能用于设置纹理单元
glUniform1i 方法确实可以用于设置纹理单元(texture unit)。在OpenGL中,纹理单元是图形硬件的一部分,它允许你同时绑定多个纹理,并在着色器程序中通过uniform变量来选择使用哪个纹理。 通常,纹理单元通过整…...

探索 Janus-1.3B:一个统一的 Any-to-Any 多模态理解与生成模型
随着多模态技术的不断发展,越来越多的模型被提出以解决跨文本与图像等多种数据类型的任务。Janus-1.3B 是由 DeepSeek 推出的一个革命性的模型,它通过解耦视觉编码并采用统一的 Transformer 架构,带来了一个高度灵活的 any-to-any 多模态框架…...
论文信息搜集
系列博客目录 文章目录 系列博客目录1.秩典型相关分析及其在视觉搜索重排序中的应用《Rank canonical correlation analysis and its application in visual search reranking》2.利用边信息的规范秩估计在多维谐波恢复中的应用《Canonical Rank Estimation Using Side Informa…...

实操给自助触摸一体机接入大模型语音交互
本文以CSK6 大模型开发板串口触摸屏为例,实操讲解触摸一体机怎样快速增加大模型语音交互功能,使用户能够通过语音在一体机上查询信息、获取智能回答及实现更多互动功能等。 在本文方案中通过CSK6大模型语音开发板采集用户语音,将语音数据传输…...
图表的放大和刷新功能
正常图表渲染显示: // 漏斗ading动画 let myChartone; // 获取配置项 let optionone; // 获取漏斗的数据 let order; let pay_order; let pay_order_num; let pay_order_num_num; let optiones; // 漏斗渲染 function polt(data) {// 从名为data的对象中获取ordata属…...

SQLServer利用QQ邮箱做SMTP服务器发邮件
环境 Microsoft SQL Server 2019 (RTM) - 15.0.2000.5 (X64) SQL Server Management Studio 15.0.18384.0 SQL Server 管理对象 (SMO) 16.100.46367.54 Microsoft .NET Framework 4.0.30319.42000 操作系统 Windows Server2019 ———————————————— 前言…...

flutter 多文本,其中文本下划线往下移动
变态需求 flutter中再满足多行文本,文本内有多个样式,并且多个样式可触发事件的情况,将其中的一部分文本的下划线往下移 方式一: 实现 使用RichText组件,主要是看中里面的WidgetSpan可以穿child为一个widget 实现源…...

7.OPEN SQL
总学习目录请点击下面连接 SAP ABAP开发从0到入职,冷冬备战-CSDN博客 目录 编辑 1.OPEN-SQL 简单回顾 R3体系 OEPN-SQL 2.OPEN-SQL 读取数据 2.1Select 语句 select 1条数据 多条数据与into AS别名 2.2INTO 结构体 内表 例子 2.3FROM 选择动态表…...
Python轻松获取抖音视频播放量
现在在gpt的加持下写一些简单的代码还是很容易的,效率高,但是要有一点基础,不然有时候发现不了问题,这些都需要经验积累和实战,最好能和工作结合起来,不然很快一段时间就忘的干干净净了,下面就是…...

YOLOv8目标检测(三*)_最佳超参数训练
YOLOv8目标检测(一)_检测流程梳理:YOLOv8目标检测(一)_检测流程梳理_yolo检测流程-CSDN博客 YOLOv8目标检测(二)_准备数据集:YOLOv8目标检测(二)_准备数据集_yolov8 数据集准备-CSDN博客 YOLOv8目标检测(三)_训练模型:YOLOv8目标检测(三)_训…...

SpringBoot SPI
参考 https://blog.csdn.net/Peelarmy/article/details/106872570 https://javaguide.cn/java/basis/spi.html#%E4%BD%95%E8%B0%93-spi SPI SPI(service provider interface)是JDK提供的服务发现机制。以JDBC为例,JDK提供JDBC接口,在包java.sql.*。MY…...

uniappp配置导航栏自定义按钮(解决首次加载图标失败问题)
1.引入iconfont的图标,只保留这两个文件 2.App.vue引入到全局中 import "./static/fonts/iconfont.css"3.pages.json中配置text为图标对应的unicode {"path": "pages/invite/invite","style": {"h5": {"…...
【Apache paimon】-- 集成 hive3.1.3 异常
目录 1、场景再现 Step1:在 hive cli beeline 执行创建 hive paimon 表 Step2:使用 insert into 写入数据 Step3:抛出异常 2、原因分析 Step1:在 yarn resource manager 作业界面查询 hive sql mr job 的 yarn log Step2:搜索job 使用的 zstd jar 版本 Step3:定…...

基于docker部署Nacos最新版本-国内稳定镜像
介绍 当前微服务架构常用的配置中心,本文推荐的是阿里云开源的nacos,截止发布本文为止,最新的nacos稳定版本为2.4.3 拉取镜像 //这个是国内目前可以下载的成熟的nacos镜像仓库,默认的docker hub需要不断的翻墙才可以下载 docke…...

云计算中的Hive操作详解
文章目录 云计算中的Hive操作详解一、引言二、Hive的基本操作1、创建表2、导入数据3、数据查询4、分区表操作 三、使用示例1、字符串处理函数2、数据类型转换 四、总结 云计算中的Hive操作详解 一、引言 Hive是云计算中一个非常重要的组件,它是基于Hadoop的一个数…...

UE4_控件蓝图_制作3D生命血条
一:效果图如下: 二、实现步骤: 1、新建敌人 右键蓝图类 选择角色, 重命名为BP_Enemytest。 双击打开,配置敌人网格体 修改位置及朝向 效果如下: 选择合适的动画蓝图类: 人物就有了动作&#x…...

11篇--图像边缘检测
图像梯度 要学习图像边缘检测,要先了解图像梯度的概念,我们正是通过梯度值来区分边缘像素点的 处于边缘附近的像素点与周围像素点的差距很大(不然不会有边缘呈现),所以给边缘附近的的梯度之变化很快,通过…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...

Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...

Ubuntu系统多网卡多相机IP设置方法
目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机,交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息,系统版本:Ubuntu22.04.5 LTS;内核版本…...

Python爬虫(52)Scrapy-Redis分布式爬虫架构实战:IP代理池深度集成与跨地域数据采集
目录 一、引言:当爬虫遭遇"地域封锁"二、背景解析:分布式爬虫的两大技术挑战1. 传统Scrapy架构的局限性2. 地域限制的三种典型表现 三、架构设计:Scrapy-Redis 代理池的协同机制1. 分布式架构拓扑图2. 核心组件协同流程 四、技术实…...

统计按位或能得到最大值的子集数目
我们先来看题目描述: 给你一个整数数组 nums ,请你找出 nums 子集 按位或 可能得到的 最大值 ,并返回按位或能得到最大值的 不同非空子集的数目 。 如果数组 a 可以由数组 b 删除一些元素(或不删除)得到,…...
【向量库】Weaviate 搜索与索引技术:从基础概念到性能优化
文章目录 零、概述一、搜索技术分类1. 向量搜索:捕捉语义的智能检索2. 关键字搜索:精确匹配的传统方案3. 混合搜索:语义与精确的双重保障 二、向量检索技术分类1. HNSW索引:大规模数据的高效引擎2. Flat索引:小规模数据…...