鸿蒙 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项目配置源码视图里加上这个代码 先获取权限,再开启…...
大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...
[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】
大家好,我是java1234_小锋老师,看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】,分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...
群晖NAS如何在虚拟机创建飞牛NAS
套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...
Ubuntu系统多网卡多相机IP设置方法
目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机,交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息,系统版本:Ubuntu22.04.5 LTS;内核版本…...
【堆垛策略】设计方法
堆垛策略的设计是积木堆叠系统的核心,直接影响堆叠的稳定性、效率和容错能力。以下是分层次的堆垛策略设计方法,涵盖基础规则、优化算法和容错机制: 1. 基础堆垛规则 (1) 物理稳定性优先 重心原则: 大尺寸/重量积木在下…...
rknn toolkit2搭建和推理
安装Miniconda Miniconda - Anaconda Miniconda 选择一个 新的 版本 ,不用和RKNN的python版本保持一致 使用 ./xxx.sh进行安装 下面配置一下载源 # 清华大学源(最常用) conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…...
基于单片机的宠物屋智能系统设计与实现(论文+源码)
本设计基于单片机的宠物屋智能系统核心是实现对宠物生活环境及状态的智能管理。系统以单片机为中枢,连接红外测温传感器,可实时精准捕捉宠物体温变化,以便及时发现健康异常;水位检测传感器时刻监测饮用水余量,防止宠物…...
