鸿蒙 OS 开发单词打卡 APP 项目实战 20240922 笔记和源码分享
配套有完整的录播课, 需要的私信.
零基础入门级别, 有点前端基础都能学会.
效果截图:
代码截图:
页面完整代码:
import { AnswerStatus } from '../enums/AnswerStatus'
import { PracticeStatus } from '../enums/PracticeStatus'
import { getRandomQuestions, Question } from '../model/Question'
import { promptAction } from '@kit.ArkUI'
import { OptionButton } from '../components/OptionButton'
import { StatItem } from '../components/StatItem'
import { ResultDialog } from '../components/ResultDialog'
import { trustedAppService } from '@kit.DeviceSecurityKit'@Entry
@Component
struct PracticePage {// 练习状态@State status: PracticeStatus = PracticeStatus.STOPPED// 题目个数@State totalQuestion: number = 3// 题目数组@State questions: Question[] = getRandomQuestions(this.totalQuestion)// 当前题目的索引@State currentIndex: number = 0// 用户选中的选项@State selectedOption: string = ""// 作答状态@State answerStatus: AnswerStatus = AnswerStatus.Answering// 已作答个数@State answeredCount: number = 0// 答对的个数@State rightCount: number = 0// 控制定时器timerController = new TextTimerController()// 总用时时间@State totalTime: number = 0// 自定义的弹窗组件控制器dialogController: CustomDialogController = new CustomDialogController({builder: ResultDialog({answeredCount: this.answeredCount,rightCount: this.rightCount,totalTime: this.totalTime,onStartFunc: () => {this.status = PracticeStatus.RUNNINGthis.timerController.start()},onCloseFunc: () => {this.questions = getRandomQuestions(this.totalQuestion)this.currentIndex = 0this.answeredCount = 0this.rightCount = 0this.totalTime = 0this.timerController.reset()this.answerStatus = AnswerStatus.Answeringthis.status = PracticeStatus.STOPPED},}),customStyle: true, // 使用自定义样式, 否则那个 x 出不来autoCancel: false, // 点击空白区域不会被自动关闭})// 统计准确率getRightPercent() {if (this.rightCount === 0) {return "0%"}return `${((this.rightCount / this.answeredCount) * 100).toFixed()}%`}// 停止练习stopPractice() {this.status = PracticeStatus.STOPPEDthis.timerController.pause()this.dialogController.open()}build() {Column() {// 统计面板Column() {// 准确率StatItem({icon: $r("app.media.ic_accuracy"),name: "准确率",fontColor: Color.Black,}) {Text(this.getRightPercent()).width(100).textAlign(TextAlign.Center)}// 进度StatItem({icon: $r("app.media.ic_progress"),name: "进度",fontColor: Color.Black,}) {Progress({ value: this.answeredCount, total: this.totalQuestion }).width(100)}// 题目个数StatItem({icon: $r("app.media.ic_count"),name: "个数",fontColor: Color.Black,}) {Button(this.totalQuestion.toString()).width(100).height(25).backgroundColor("#EBEBEB").enabled(this.status === PracticeStatus.STOPPED).onClick(() => {TextPickerDialog.show({range: ["5", "10", "20", "50", "100"],value: this.totalQuestion.toString(), // 默认值onAccept: (result) => {this.totalQuestion = parseInt(result.value.toString())this.questions = getRandomQuestions(this.totalQuestion)}})})}// 计时StatItem({icon: $r("app.media.ic_timer"),name: "用时",fontColor: Color.Black,}) {Row() {TextTimer({ controller: this.timerController }).onTimer((utc, elapsedTime) => {this.totalTime = elapsedTime})}.width(100).justifyContent(FlexAlign.Center)}}.statBgStyle()// 题目Column() {Text(this.questions[this.currentIndex].word).wordStyle()Text(this.questions[this.currentIndex].sentence).sentenceStyle()}// 选项Column({ space: 15 }) {ForEach(this.questions[this.currentIndex].options,(item: string) => {OptionButton({option: item,answer: this.questions[this.currentIndex].answer,selectedOption: this.selectedOption,answerStatus: this.answerStatus,}).enabled(this.answerStatus === AnswerStatus.Answering).onClick(() => {// 判断练习状态if (this.status !== PracticeStatus.RUNNING) {promptAction.showToast({ message: "请先点击开始测试按钮" })return}// 先将答题状态改为已作答this.answerStatus = AnswerStatus.Answered// 判断答案是否正确this.selectedOption = itemthis.answeredCount++if (this.questions[this.currentIndex].answer === this.selectedOption) {this.rightCount++}// 判断题目状态if (this.currentIndex < this.questions.length - 1) {setTimeout(() => {this.currentIndex++this.answerStatus = AnswerStatus.Answering}, 500)} else {// 停止测试this.stopPractice()}})},(item: string) => this.questions[this.currentIndex].word + "_" + item,)}// 控制按钮Row({ space: 20 }) {Button("停止测试").controlButtonStyle(Color.Transparent,this.status === PracticeStatus.STOPPED ? Color.Gray : Color.Black,this.status === PracticeStatus.STOPPED ? Color.Gray : Color.Black,).enabled(this.status !== PracticeStatus.STOPPED).onClick(() => this.stopPractice())Button(this.status === PracticeStatus.RUNNING ? "暂停测试" : "开始测试").controlButtonStyle(this.status === PracticeStatus.RUNNING ? "#666666" : Color.Black,this.status === PracticeStatus.RUNNING ? "#666666" : Color.Black,Color.White,).stateEffect(false).onClick(() => {if (this.status === PracticeStatus.RUNNING) {// 暂停测试this.status = PracticeStatus.PAUSEDthis.timerController.pause()} else {// 开始测试this.status = PracticeStatus.RUNNINGthis.timerController.start()}})}}.practiceBgStyle()}
}// 页面背景
@Extend(Column)
function practiceBgStyle() {.width("100%").height("100%").backgroundImage($r("app.media.img_practice_bg")).backgroundImageSize({ width: "100%", height: "100%" }).justifyContent(FlexAlign.SpaceEvenly)
}// 统计面板背景
@Styles
function statBgStyle() {.backgroundColor(Color.White).width("90%").borderRadius(10).padding(20)
}// 单词样式
@Extend(Text)
function wordStyle() {.fontSize(50).fontWeight(FontWeight.Bold)
}// 例句样式
@Extend(Text)
function sentenceStyle() {.height(40).fontSize(16).fontColor("#9BA1A5").fontWeight(FontWeight.Medium).width("80%").textAlign(TextAlign.Center)
}// 控制按钮样式
@Extend(Button)
function controlButtonStyle(bgColor: ResourceColor,borderColor: ResourceColor,fontColor: ResourceColor,
) {.fontSize(16).borderWidth(1).backgroundColor(bgColor).borderColor(borderColor).fontColor(fontColor)
}
选项按钮组件完整代码:
import { AnswerStatus } from '../enums/AnswerStatus'
import { OptionStatus } from '../enums/OptionStatus'@Component
export struct OptionButton {// 选项内容option: string = ""// 答案answer: string = ""// 选项状态@State optionStatus: OptionStatus = OptionStatus.DEFAULT// 用户选中的选项@Prop selectedOption: string = ""// 属性@Prop @Watch("onAnswerStatusChange") answerStatus: AnswerStatus = AnswerStatus.Answering// 监听器方法onAnswerStatusChange() {if (this.option === this.answer) {// 答案正确this.optionStatus = OptionStatus.RIGHT} else {if (this.option === this.selectedOption) {// 如果当前选项按钮是被选中但错误的按钮this.optionStatus = OptionStatus.ERROR} else {this.optionStatus = OptionStatus.DEFAULT}}}// 获取背景颜色getBgColor() {switch (this.optionStatus) {case OptionStatus.RIGHT:return "#1DBF7B"case OptionStatus.ERROR:return "#FA635F"default:return Color.White}}build() {Stack() {Button(this.option).optionButtonStyle(this.getBgColor(), // 动态获取背景颜色this.optionStatus === OptionStatus.DEFAULT ? Color.Black : Color.White,)// 根据状态设置不同的图标if (this.optionStatus === OptionStatus.RIGHT) {Image($r("app.media.ic_right")).width(22).height(22).offset({ x: 10 })} else if (this.optionStatus === OptionStatus.ERROR) {Image($r("app.media.ic_wrong")).width(22).height(22).offset({ x: 10 })}}.alignContent(Alignment.Start)}
}// 选项按钮样式
@Extend(Button)
function optionButtonStyle(bgColor: ResourceColor, fontColor: ResourceColor) {.width(240).height(48).fontSize(16).type(ButtonType.Normal).fontWeight(FontWeight.Medium).borderRadius(8).backgroundColor(bgColor).fontColor(fontColor)
}
弹窗组件完整代码:
import { millisecondsToTimeStr } from '../utils/DateUtil'
import { StatItem } from './StatItem'@CustomDialog
export struct ResultDialog {answeredCount: number = 0 // 已答题个数rightCount: number = 0 // 正确个数totalTime: number = 0 // 总计耗时// 再来一局开始执行的函数onStartFunc: () => void = () => {}// 在关闭弹窗时触发方法onCloseFunc: () => void = () => {}// 弹窗控制器controller: CustomDialogController = new CustomDialogController({builder: ResultDialog()})// 统计准确率getRightPercent() {if (this.rightCount === 0) {return "0%"}return `${((this.rightCount / this.answeredCount) * 100).toFixed()}%`}build() {Column({ space: 10 }) {// 右上角有个 X 的按钮Image($r("app.media.ic_close")).width(25).height(25).alignSelf(ItemAlign.End).onClick(() => {this.controller.close() // 关闭弹窗this.onCloseFunc() // 触发关闭的函数})// 主体内容Column({ space: 10 }) {// 图片Image($r("app.media.img_post")).width("100%").borderRadius(10)// 用时StatItem({icon: $r("app.media.ic_timer"),name: "用时",fontColor: Color.Black}) {Text(millisecondsToTimeStr(this.totalTime))}// 准确率StatItem({icon: $r("app.media.ic_accuracy"),name: "准确率",fontColor: Color.Black}) {Text(this.getRightPercent())}// 个数StatItem({icon: $r("app.media.ic_count"),name: "个数",fontColor: Color.Black}) {Text(this.answeredCount.toString())}// 分割线Divider()// 控制按钮Row({ space: 30 }) {Button("再来一局").controlButtonStyle(Color.Transparent,Color.Black,Color.Black,).onClick(() => {this.controller.close()this.onCloseFunc() // 先关闭this.onStartFunc() // 再启动})Button("登录打卡").controlButtonStyle(Color.Black,Color.Black,Color.White,).onClick(() => {this.controller.close()this.onCloseFunc() // 先关闭// TODO: 登录并打卡})}}.backgroundColor(Color.White).width("100%").padding(20).borderRadius(10)}.backgroundColor(Color.Transparent).width("80%")}
}// 控制按钮样式
@Extend(Button)
function controlButtonStyle(bgColor: ResourceColor,borderColor: ResourceColor,fontColor: ResourceColor,
) {.fontSize(16).borderWidth(1).backgroundColor(bgColor).borderColor(borderColor).fontColor(fontColor)
}
代码比较多, 需要整套完整代码的可以私信我获取.
相关文章:

鸿蒙 OS 开发单词打卡 APP 项目实战 20240922 笔记和源码分享
配套有完整的录播课, 需要的私信. 零基础入门级别, 有点前端基础都能学会. 效果截图: 代码截图: 页面完整代码: import { AnswerStatus } from ../enums/AnswerStatus import { PracticeStatus } from ../enums/PracticeStatus import { getRandomQuestions, Question …...

力扣P1706全排列问题 很好的引入暴力 递归 回溯 dfs
代码思路是受一个洛谷题解里面大佬的启发。应该算是一个dfs和回溯的入门题目,很好的入门题目了下面我会先给我原题解思路我想可以很快了解这个思路。下面是我自己根据力扣大佬写的。 我会进行详细讲解并配上图辅助理解大家请往下看 #include<iostream> #inc…...

使用Python Pandas导入数据库和文件数据
大家好,在数据分析过程中,数据的导入是第一步,也是最重要的一步。Python的Pandas提供了强大的数据读取功能,支持从多种数据源导入数据,包括CSV、Excel、JSON、SQL数据库、网页等。Pandas库不仅能够处理常见的文件格式&…...

lef 中antenna解释
这些规则主要涉及集成电路设计中的天线效应(Antenna Effect)和通孔(Via)设计规则。 ANTENNAAREADIFFREDUCEPWL 这条规则指定了一个分段线性函数,用于根据连接到切割层的扩散区面积来计算cut_area的缩减因子。扩散区面积值应从0开始单调增加。如果没有定义此规则,PAR(mi)方程中的…...

初试Bootstrap前端框架
文章目录 一、Bootstrap概述二、Bootstrap实例1、创建网页2、编写代码3、代码说明4、浏览网页,查看结果5、登录按钮事件处理6、浏览网页,查看结果 三、实战小结 一、Bootstrap概述 大家好,今天我们将一起学习一个非常流行的前端框架——Boot…...

mysql数据库:超键、候选键、主键与外键
mysql数据库:超键、候选键、主键与外键 1、超键(Superkey)2、候选键(Candidate Key)3、主键(Primary Key)4、外键(Foreign Key) 💖The Begin💖点点…...

音频转MP3格式困难?如何轻松实现wav转mp3?
格式多样化为我们带来了灵活性和创意的无限可能,但同时,不同格式间的转换也成为了不少用户面临的难题。尤其是当你手握珍贵的WAV音频文件,却希望它们能在更多设备上流畅播放或节省存储空间时,wav转mp3的需求便应运而生。WAV以其无…...

基于vue框架的大连盐业有限公司生产管理系统的设计与实现3hk5y(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。
系统程序文件列表 项目功能:计划员,工艺员,生产建模,生产计划,生产信息,生产监视,工艺质量,盐政信息 开题报告内容 一、引言 随着信息技术的飞速发展和市场竞争的日益激烈,传统盐业企业如大连盐业有限公司正面临着转型升级的迫切需求。传统管理模式下…...

《深入理解JAVA虚拟机(第2版)》- 第13章 - 学习笔记【终章】
第13章 线程安全与锁优化 13.1 概述 面向过程的编程思想 将数据和过程独立分开,数据是问题空间中的客体,程序代码是用来处理数据的,这种站在计算机角度来抽象和解决问题的思维方式,称为面向对象的编程思想。 面向对象的编程思想…...

网络工程师学习笔记——网络互连与互联网(三)
TCP三次握手 建立TCP连接是通过三次握手实现的,采用三报文握手主要是为了防止已失效的连接请求报文突然又传送到了,因而产生错误 主动发起TCP连接建立的称为客户端 被动等待的为TCP服务器,二者之间需要交换三个TCP报文段 首先是客户端主动…...

【Tomcat】常见面试题整理 共34题
文章目录 1. 简述什么是Tomcat?2. Tomcat的缺省端口是多少,怎么修改?3. 简述Tomcat 目录结构及作用4. 简述Tomcat有几种部署方式?5. 简述Tomcat容器是如何创建servlet类实例?6. Tomcat有哪几种Connector运行模式&#…...

到时间没回家又不接电话?如何迅速确定孩子的位置?
当孩子未按时回家且无法通过电话联系时,家长往往会感到焦虑。此时,如何迅速确定孩子的位置成为许多家长迫切需要解决的问题。 利用智能手机定位技术是最常见的方法之一。大多数智能手机都内置GPS定位功能,通过“查找设备”应用,家…...

接口自动化--commons内容详解-02
上篇文章主要讲解了接口自动化主要架构框架,这篇文庄主要讲解commons中的内容 1. requests_utils.py 首先讲解这个工具类,主要是因为在接口自动化中,基本都有的接口都是发送请求,获取响应结果,唯一不同的是࿰…...

WanFangAi论文写作研究生论文写作神器在线生成真实数据,标注参考文献位置,表格公式代码流程图查重20以内,研究生论文写作技巧
WanFangAi是一个专业的学术论文辅助平台,它提供了一系列工具来帮助用户提升论文写作的效率和质量。以下是WanFangAi的一些核心功能:1.主题探索与文献搜索:用户可以输入关键词和研究领域,WanFangAi会迅速推荐合适的论文主题并提供相关的文献搜索服务。系统…...

cv2.waitkey(30) 按键盘无效
cv2.imshow("detection", color_image) # 窗口显示,显示名为 Capture_Videok cv2.waitKey(100) & 0xFF # 每帧数据延时 1ms,延时不能为 0,否则读取的结果会是静态帧 if k ord(s): # 键盘按一下s, 保存当前照片和机械臂位姿…...

【洛谷】P10417 [蓝桥杯 2023 国 A] 第 K 小的和 的题解
【洛谷】P10417 [蓝桥杯 2023 国 A] 第 K 小的和 的题解 题目传送门 题解 CSP-S1 补全程序,致敬全 A 的答案,和神奇的预言家。 写一下这篇的题解说不定能加 CSP 2024 的 RP 首先看到 k k k 这么大的一个常数,就想到了二分。然后写一个判…...

Ubuntu24.04 安装ssh开启22端口及允许root用户远程登录
1、安装openssh-server插件开启22端口访问 # 安装ssh会默认启动服务并开启22端口 apt update apt install openssh-server 2、开启root用户远程访问 激活root用户,设置root用户登录密码 hunterlocalhost:/$ sudo passwd root New password: Retype new password…...

STM32基础学习笔记-DHT11单总线协议面试基础题7
第七章、DHT11: 单总线协!议 常见问题 1、DHT11是什么 ?有什么特性 ? 2、单总线协议是什么 ?原理 ?DHT11的单总线协议的组成 ? ## 1、DHT11定义 单总线协议是一种用于在多个设备之间进行通信的协议,所有…...

Redisson分布式锁的概念和使用
Redisson分布式锁的概念和使用 一 简介1.1 什么是分布式锁?1.2 Redisson分布式锁的原理1.3 Redisson分布式锁的优势1.4 Redisson分布式锁的应用场景 二 案例2.1 锁竞争案例2.2 看门狗案例2.3 参考文章 前言 这是我在这个网站整理的笔记,有错误的地方请指出ÿ…...

uniapp小程序持续获取用户位置信息,后台位置获取
做一个小程序持续获取用户位置信息的功能,即使小程序切换到后台也能继续获取,getLocation这个api只有小程序在前台才能获取位置,所以不用这个 先申请一个腾讯地图key 在uniapp项目配置源码视图里加上这个代码 先获取权限,再开启…...
优化算法(五)—梯度下降算法(附MATLAB程序)
梯度下降算法(Gradient Descent)是一种常用的优化算法,用于寻找函数的局部最小值。它通过沿着函数梯度的反方向迭代地调整变量,以逐步找到最优解。梯度下降广泛应用于机器学习和深度学习中,特别是在训练模型时优化损失…...

TypeScript 设计模式之【单例模式】
文章目录 **单例模式**: 独一无二的特工我们为什么需要这样的特工?单例模式的秘密:如何培养这样的特工?特工的利与害代码实现单例模式的主要优点单例模式的主要缺点单例模式的适用场景总结 单例模式: 独一无二的特工 单例模式就像是一个秘密组织里的特殊特工。这…...

UDP与TCP那个传输更快
UDP(用户数据报协议)和 TCP(传输控制协议)是互联网协议栈中常用的两种传输层协议。它们在设计和应用上存在一些显著的差异,导致在传输速度和可靠性等方面表现不同。以下是它们之间的比较,特别是关于传输速度…...

如何把PDF样本册转换为网址链接
随着互联网的普及,将纸质或PDF格式的样本册转化为网址链接,以便于在线浏览和分享,变得越来越重要。本文将为您详细讲解如何将PDF样本册转换为网址链接,让您轻松实现线上展示和分享。 一、了解PDF样本册与网址链接 1. PDF样本册…...

centos7 semanage 离线安装 SELinux
centos7 semanage 离线安装 还是参考一下 换成阿里云的源 之后 ,在线更新不,不要用离线安装 centos7 更新 yum源 为 阿里云 LTS https://blog.csdn.net/wowocpp/article/details/142517908 CentOS7安装时使用"基础服务器"选项安装, 后发现没…...

磨具生产制造9人共用一台工作站
随着技术的不断进步与工业自动化的深入发展,如何优化生产流程、提高设备利用率成为了众多企业面临的重大课题。那么在磨具生产制造中实现9人共用一台工作站呢? 一、背景与挑战 在磨具制造行业,高精度、高效率的生产要求与复杂多变的工艺流程…...

Qt clicked()、clicked(bool)、toggled(bool)信号的区别和联系
clicked() 信号 所属控件:clicked()信号是QAbstractButton类(及其子类,如QPushButton、QRadioButton、QCheckBox等)的一个信号。clicked信号可以说是许多控件(特别是按钮类控件,如QPushButton)…...

nginx实现负载均衡的分发策略
文章目录 分发策略 分发策略 轮询策略 轮询策略是最简单的负载均衡策略之一。Nginx 默认采用轮询方式将请求分发到不同的后端服务器。它将请求按照顺序轮流分配给每个后端服务器,不论服务器当前的负载情况如何。这种策略适合后端服务器性能相近且无太大差异的场景。…...

【Python】用代码片段掌握Python核心功能
探索各种用户输入值 Python 是一种多才多艺的编程语言,广泛应用于从 Web 开发到数据分析的各种场景。这篇文章将通过实际的代码片段带你了解 Python 中的几个基本概念和操作。无论你是初学者还是想重温一下知识点,这些例子都会给你带来宝贵的见解。 输…...

JVM 内存模型
JVM 内存模型 对于 Java 程序员来说,在虚拟机自动内存管理机制下,不再需要像 C/C程序开发程序员这样为每一个 new 操作去写对应的 delete/free 操作,不容易出现内存泄漏和内存溢出问题。正是因为 Java程序把内存控制权利交给 JVM 虚拟机。一旦出现内存泄漏和溢出方面的问题,如果…...