【1】引言(完整代码在最后面)

本项目旨在实现一个简单的“抛硬币”功能,用户可以通过点击屏幕上的地鼠图标来模拟抛硬币的过程。应用会记录并显示硬币正面(地鼠面)和反面(数字100面)出现的次数。为了增强用户体验,我们还添加了动画效果,使抛硬币的过程更加生动有趣。

【2】环境准备

电脑系统:windows 10

开发工具:DevEco Studio NEXT Beta1 Build Version: 5.0.3.806

工程版本:API 12

真机:mate60 pro

语言:ArkTS、ArkUI

【3】应用结构

应用主要由两个部分组成:地鼠组件(Hamster)和主页面组件(CoinTossPage)。

地鼠组件(Hamster)

地鼠组件是应用的核心视觉元素之一,负责展示地鼠的形象。该组件通过@Component装饰器定义,并接收一个属性cellWidth,用于控制组件的大小。

主页面组件(CoinTossPage)

主页面组件是整个应用的入口点,负责组织和管理各个UI元素。该组件同样通过@Component装饰器定义,并包含多个状态变量用于跟踪硬币的状态和动画进度。

【4】功能解析

1. 地鼠组件:

• 通过Stack布局组合多个图形元素,创建了一个地鼠的形象。

• 每个图形元素都设置了具体的尺寸、颜色、边框等样式,并通过margin属性调整位置。

2. 主页面组件:

• 顶部有一个“抛硬币”的标题,下方是一个行布局,用于展示地鼠组件及正反两面出现的次数。

• 地鼠组件被放置在一个圆形区域内,背景采用线性渐变色。

• 点击地鼠时,会触发一系列动画效果,模拟硬币抛起再落下的过程。

• 通过计算最终的角度,判断是正面还是反面朝上,并更新相应的计数。

【完整代码】

// 定义地鼠组件
@Component
struct Hamster {
@Prop cellWidth: number // 单元格宽度 build() {
Stack() { // 创建一个堆叠布局
// 身体
Text()
.width(`${this.cellWidth / 2}lpx`)// 宽度为单元格宽度的一半
.height(`${this.cellWidth / 3 * 2}lpx`)// 高度为单元格高度的2/3
.backgroundColor("#b49579")// 背景颜色
.borderRadius({ topLeft: '50%', topRight: '50%' })// 圆角
.borderColor("#2a272d")// 边框颜色
.borderWidth(1) // 边框宽度
// 嘴巴
Ellipse()
.width(`${this.cellWidth / 4}lpx`)// 嘴巴的宽度
.height(`${this.cellWidth / 5}lpx`)// 嘴巴的高度
.fillOpacity(1)// 填充不透明度
.fill("#e7bad7")// 填充颜色
.stroke("#563e3f")// 边框颜色
.strokeWidth(1)// 边框宽度
.margin({ top: `${this.cellWidth / 6}lpx` }) // 上边距
// 左眼睛
Ellipse()
.width(`${this.cellWidth / 9}lpx`)// 左眼睛的宽度
.height(`${this.cellWidth / 6}lpx`)// 左眼睛的高度
.fillOpacity(1)// 填充不透明度
.fill("#313028")// 填充颜色
.stroke("#2e2018")// 边框颜色
.strokeWidth(1)// 边框宽度
.margin({ bottom: `${this.cellWidth / 3}lpx`, right: `${this.cellWidth / 6}lpx` }) // 下边距和右边距
// 右眼睛
Ellipse()
.width(`${this.cellWidth / 9}lpx`)// 右眼睛的宽度
.height(`${this.cellWidth / 6}lpx`)// 右眼睛的高度
.fillOpacity(1)// 填充不透明度
.fill("#313028")// 填充颜色
.stroke("#2e2018")// 边框颜色
.strokeWidth(1)// 边框宽度
.margin({ bottom: `${this.cellWidth / 3}lpx`, left: `${this.cellWidth / 6}lpx` }) // 下边距和左边距
// 左眼瞳
Ellipse()
.width(`${this.cellWidth / 20}lpx`)// 左眼瞳的宽度
.height(`${this.cellWidth / 15}lpx`)// 左眼瞳的高度
.fillOpacity(1)// 填充不透明度
.fill("#fefbfa")// 填充颜色
.margin({ bottom: `${this.cellWidth / 2.5}lpx`, right: `${this.cellWidth / 6}lpx` }) // 下边距和右边距
// 右眼瞳
Ellipse()
.width(`${this.cellWidth / 20}lpx`)// 右眼瞳的宽度
.height(`${this.cellWidth / 15}lpx`)// 右眼瞳的高度
.fillOpacity(1)// 填充不透明度
.fill("#fefbfa")// 填充颜色
.margin({ bottom: `${this.cellWidth / 2.5}lpx`, left: `${this.cellWidth / 6}lpx` }) // 下边距和左边距
}.width(`${this.cellWidth}lpx`).height(`${this.cellWidth}lpx`) // 设置组件的宽度和高度
}
} // 定义页面组件
@Entry
@Component
struct CoinTossPage {
@State cellWidth: number = 50 // 单元格宽度
@State headsCount: number = 0 // 正面朝上的次数
@State tailsCount: number = 0 // 反面朝上的次数
@State rotationAngle: number = 0 // 旋转角度
@State verticalOffset: number = 0 // 纵向位移
@State isAnimRun: boolean = false // 动画是否正在执行 build() {
Column() {
// 页面标题
Text('抛硬币')
.height(50)// 高度设置为50
.width('100%')// 宽度设置为100%
.textAlign(TextAlign.Center)// 文本居中对齐
.fontColor("#fefefe")// 字体颜色
.fontSize(20); // 字体大小 // 显示地鼠和计数
Row({ space: 20 }) {
Stack() {
Hamster({ cellWidth: this.cellWidth }) // 创建地鼠组件
}
.borderRadius('50%') // 设置圆角
.width(`${this.cellWidth}lpx`) // 设置宽度
.height(`${this.cellWidth}lpx`) // 设置高度
.linearGradient({
// 设置线性渐变背景
direction: GradientDirection.LeftBottom,
colors: [['#ebcf2f', 0.0], ['#fef888', 0.5], ['#ebcf2f', 1.0]]
}); // 显示反面朝上的次数
Text(`${this.tailsCount}`)
.fontSize(20)
.fontColor("#fefefe"); Stack() {
// 显示100
Text("100")
.fontColor("#9f7606")
.fontSize(`${this.cellWidth / 2}lpx`);
}
.borderRadius('50%') // 设置圆角
.width(`${this.cellWidth}lpx`) // 设置宽度
.height(`${this.cellWidth}lpx`) // 设置高度
.linearGradient({
// 设置线性渐变背景
direction: GradientDirection.LeftBottom,
colors: [['#ebcf2f', 0.0], ['#fef888', 0.5], ['#ebcf2f', 1.0]]
}); // 显示正面朝上的次数
Text(`${this.headsCount}`)
.fontSize(20)
.fontColor("#fefefe"); }.width('100%').justifyContent(FlexAlign.Center); // 设置宽度和内容居中对齐 Stack() {
Stack() {
// 创建放大版地鼠组件
Hamster({ cellWidth: this.cellWidth * 3 })
.visibility(this.isHeadsFaceUp() ? Visibility.Visible : Visibility.Hidden); // 根据状态显示或隐藏 // 显示100
Text("100")
.fontColor("#9f7606")// 字体颜色
.fontSize(`${this.cellWidth / 2 * 3}lpx`)// 字体大小
.visibility(!this.isHeadsFaceUp() ? Visibility.Visible : Visibility.Hidden)// 根据状态显示或隐藏
.rotate({
// 旋转180度
x: 1,
y: 0,
z: 0,
angle: 180
});
}
.borderRadius('50%') // 设置圆角
.width(`${this.cellWidth * 3}lpx`) // 设置宽度
.height(`${this.cellWidth * 3}lpx`) // 设置高度
.linearGradient({
// 设置线性渐变背景
direction: GradientDirection.LeftBottom,
colors: [['#ebcf2f', 0.0], ['#fef888', 0.5], ['#ebcf2f', 1.0]]
})
.rotate({
// 根据当前角度旋转
x: 1,
y: 0,
z: 0,
angle: this.rotationAngle
})
.translate({ x: 0, y: this.verticalOffset }) // 设置纵向位移
.onClick(() => { // 点击事件处理 if (this.isAnimRun) {
return;
}
this.isAnimRun = true let maxAnimationSteps = 2 * (10 + Math.floor(Math.random() * 10)); // 计算最大动画次数
let totalAnimationDuration = 2000; // 动画总时长 // 第一次动画,向上抛出
animateToImmediately({
duration: totalAnimationDuration / 2, // 动画时长为总时长的一半
onFinish: () => { // 动画完成后的回调
// 第二次动画,向下落
animateToImmediately({
duration: totalAnimationDuration / 2,
onFinish: () => {
this.rotationAngle = this.rotationAngle % 360; // 确保角度在0到360之间
// 判断当前显示的面
if (this.isHeadsFaceUp()) { // 如果是地鼠面
this.tailsCount++; // 反面朝上的次数加1
} else { // 如果是反面
this.headsCount++; // 正面朝上的次数加1
}
this.isAnimRun = false
}
}, () => {
this.verticalOffset = 0; // 重置纵向位移
});
}
}, () => {
// 设置纵向位移,模拟抛硬币的效果
this.verticalOffset = -100 * (1 + Math.floor(Math.random() * 5)); // 随机设置向上的位移
}); // 循环动画,增加旋转效果
for (let i = 0; i < maxAnimationSteps; i++) {
animateToImmediately({
delay: i * totalAnimationDuration / maxAnimationSteps, // 设置每次动画的延迟
duration: 100, // 每次动画的持续时间
onFinish: () => {
// 动画完成后的回调
}
}, () => {
this.rotationAngle += 90; // 每次增加90度旋转
});
}
}); }.width('100%').layoutWeight(1).align(Alignment.Bottom).padding({ bottom: 80 }); // 设置组件的宽度、权重、对齐方式和底部内边距
}
.height('100%') // 设置整个页面的高度
.width('100%') // 设置整个页面的宽度
.backgroundColor("#0b0d0c"); // 设置背景颜色
} // 判断当前是否显示地鼠面
isHeadsFaceUp() {
let normalizedAngle = this.rotationAngle % 360; // 规范化角度
// 判断角度范围,确定是否显示地鼠面
if (normalizedAngle >= 0 && normalizedAngle < 90 || normalizedAngle >= 270 && normalizedAngle <= 360) {
return true; // 显示地鼠面
}
return false; // 显示反面
}
}

  

鸿蒙NEXT开发案例:抛硬币的更多相关文章

  1. 基于JWT的Token开发案例

    代码地址如下:http://www.demodashi.com/demo/12531.html 0.准备工作 0-1运行环境 jdk1.8 maven 一个能支持以上两者的代码编辑器,作者使用的是ID ...

  2. 最全华为鸿蒙 HarmonyOS 开发资料汇总

    开发 本示例基于 OpenHarmony 下的 JavaScript UI 框架,进行项目目录解读,JS FA.常用和自定义组件.用户交互.JS 动画的实现,通过本示例可以基本了解和学习到 JavaS ...

  3. 使用Jquery+EasyUI 进行框架项目开发案例讲解之五 模块(菜单)管理源码分享

    http://www.cnblogs.com/huyong/p/3454012.html 使用Jquery+EasyUI 进行框架项目开发案例讲解之五  模块(菜单)管理源码分享    在上四篇文章 ...

  4. 使用Jquery+EasyUI 进行框架项目开发案例讲解之四 组织机构管理源码分享

    http://www.cnblogs.com/huyong/p/3404647.html 在上三篇文章  <使用Jquery+EasyUI进行框架项目开发案例讲解之一---员工管理源码分享> ...

  5. 使用Jquery+EasyUI 进行框架项目开发案例讲解之三---角色管理源码分享

    使用Jquery+EasyUI 进行框架项目开发案例讲解之三 角色管理源码分享    在上两篇文章  <使用Jquery+EasyUI进行框架项目开发案例讲解之一---员工管理源码分享> ...

  6. 使用Jquery+EasyUI 进行框架项目开发案例讲解之二---用户管理源码分享

    使用Jquery+EasyUI 进行框架项目开发案例讲解之二 用户管理源码分享   在上一篇文章<使用Jquery+EasyUI进行框架项目开发案例讲解之一---员工管理源码分享>我们分享 ...

  7. 【推荐】使用Jquery+EasyUI进行框架项目开发案例讲解之一---员工管理源码分享

    使用Jquery+EasyUI 进行框架项目开发案例讲解之一 员工管理源码分享   在开始讲解之前,我们先来看一下什么是Jquery EasyUI?jQuery EasyUI是一组基于jQuery的U ...

  8. 模拟抛硬币(C语言实现)

    实现代码: #include<stdio.h> #include<stdlib.h> int heads() { ; } int main(int argc, char *ar ...

  9. 使用Jquery+EasyUI进行框架项目开发案例解说之中的一个---员工管理源代码分享

    使用Jquery+EasyUI 进行框架项目开发案例解说之中的一个 员工管理源代码分享 在開始解说之前,我们先来看一下什么是Jquery EasyUI?jQuery EasyUI是一组基于jQuery ...

  10. 百度UEditor开发案例(JSP)

    本案例的开发环境:MyEclipse+tomcat+jdk     本案例的开发内容: 用百度编辑器发布新闻(UEditor的初始化开发部署) 编辑已发过的新闻(UEditor的应用——编辑旧文章) ...

随机推荐

  1. T113s工业套件简述

    T113s工业套件简述 提示 T113开发交流QQ群:120575746 此开发板的任何问题都可以在我们的论坛交流讨论 https://forums.100ask.net/c/aw/ 硬件简述​ 10 ...

  2. Tesla 开发者 API 指南:BLE 密钥 – 身份验证和车辆命令

    注意:本工具只能运行于 mac 或者 linux, win下不支持. 1. 克隆项目到本地 https://github.com/teslamotors/vehicle-command.git 2. ...

  3. k8s中文文档

    地址:http://docs.kubernetes.org.cn/122.html

  4. 异源数据同步 → DataX 为什么要支持 kafka?

    开心一刻 昨天发了一条朋友圈:酒吧有什么好去的,上个月在酒吧当服务员兼职,一位大姐看上了我,说一个月给我 10 万,要我陪她去上海,我没同意 朋友评论道:你没同意,为什么在上海? 我回复到:上个月没同 ...

  5. 折腾 Quickwit,Rust 编写的分布式搜索引擎 - 可观测性之分布式追踪

    概述 分布式追踪是一种跟踪应用程序请求流经不同服务(如前端.后端.数据库等)的过程.它是一个强大的工具,可以帮助您了解应用程序的工作原理并调试性能问题. Quickwit 是一个用于索引和搜索非结构化 ...

  6. windows 误删除\AppData\Local\文件夹后 异常的修复

    背景:清除Temp文件夹时,路径复制错误,少复制了Temp,导致删除了文件夹 C:\Users\username\AppData\Local\ 异常现象: 估计删除Local文件夹后,出现的问题应该会 ...

  7. 手写一个Promise.all

    Promise.all 特性: 1. 按顺序返回结果数组; 2. 当所有promise完成才返回; 3. 返回第一个报错的promise的信息; 直接上代码: Promise._all = funct ...

  8. VMware安装CentOS7及远程登录详细教程

    写在前面 主要使用软件: VMware Workstation Pro17 Navicat Premium17 Xshell7 Xftp7 1.在虚拟机安装CentOS7 访问阿里云镜像站 ,选择标记 ...

  9. SQL Server – Transaction & Isolation 事务与隔离

    前言 上回在谈到 Concurrency 并发控制 时, 有提到过事务的概念. 这篇就补上它具体的实现. 以前写过相关的文章: sql server 学习笔记 (nested transaction ...

  10. 理解IO多路复用

    I/O 多路复用是什么? I/O 多路复用是用户程序通过复用一个线程来服务多个 I/O 事件的机制,我们也可以将他说成是一个线程服务多个文件描述符 fd,而 I/O 多路复用是在操作系统层面实现提供的 ...