当前位置: 首页 > news >正文

鸿蒙 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和回溯的入门题目&#xff0c;很好的入门题目了下面我会先给我原题解思路我想可以很快了解这个思路。下面是我自己根据力扣大佬写的。 我会进行详细讲解并配上图辅助理解大家请往下看 #include<iostream> #inc…...

使用Python Pandas导入数据库和文件数据

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

lef 中antenna解释

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

初试Bootstrap前端框架

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

mysql数据库:超键、候选键、主键与外键

mysql数据库&#xff1a;超键、候选键、主键与外键 1、超键&#xff08;Superkey&#xff09;2、候选键&#xff08;Candidate Key&#xff09;3、主键&#xff08;Primary Key&#xff09;4、外键&#xff08;Foreign Key&#xff09; &#x1f496;The Begin&#x1f496;点点…...

音频转MP3格式困难?如何轻松实现wav转mp3?

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

基于vue框架的大连盐业有限公司生产管理系统的设计与实现3hk5y(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;计划员,工艺员,生产建模,生产计划,生产信息,生产监视,工艺质量,盐政信息 开题报告内容 一、引言 随着信息技术的飞速发展和市场竞争的日益激烈&#xff0c;传统盐业企业如大连盐业有限公司正面临着转型升级的迫切需求。传统管理模式下…...

《深入理解JAVA虚拟机(第2版)》- 第13章 - 学习笔记【终章】

第13章 线程安全与锁优化 13.1 概述 面向过程的编程思想 将数据和过程独立分开&#xff0c;数据是问题空间中的客体&#xff0c;程序代码是用来处理数据的&#xff0c;这种站在计算机角度来抽象和解决问题的思维方式&#xff0c;称为面向对象的编程思想。 面向对象的编程思想…...

网络工程师学习笔记——网络互连与互联网(三)

TCP三次握手 建立TCP连接是通过三次握手实现的&#xff0c;采用三报文握手主要是为了防止已失效的连接请求报文突然又传送到了&#xff0c;因而产生错误 主动发起TCP连接建立的称为客户端 被动等待的为TCP服务器&#xff0c;二者之间需要交换三个TCP报文段 首先是客户端主动…...

【Tomcat】常见面试题整理 共34题

文章目录 1. 简述什么是Tomcat&#xff1f;2. Tomcat的缺省端口是多少&#xff0c;怎么修改&#xff1f;3. 简述Tomcat 目录结构及作用4. 简述Tomcat有几种部署方式&#xff1f;5. 简述Tomcat容器是如何创建servlet类实例&#xff1f;6. Tomcat有哪几种Connector运行模式&#…...

到时间没回家又不接电话?如何迅速确定孩子的位置?

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

接口自动化--commons内容详解-02

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

WanFangAi论文写作研究生论文写作神器在线生成真实数据,标注参考文献位置,表格公式代码流程图查重20以内,研究生论文写作技巧

WanFangAi是一个专业的学术论文辅助平台&#xff0c;它提供了一系列工具来帮助用户提升论文写作的效率和质量。以下是WanFangAi的一些核心功能:1.主题探索与文献搜索:用户可以输入关键词和研究领域&#xff0c;WanFangAi会迅速推荐合适的论文主题并提供相关的文献搜索服务。系统…...

cv2.waitkey(30) 按键盘无效

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

【洛谷】P10417 [蓝桥杯 2023 国 A] 第 K 小的和 的题解

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

Ubuntu24.04 安装ssh开启22端口及允许root用户远程登录

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

STM32基础学习笔记-DHT11单总线协议面试基础题7

第七章、DHT11: 单总线协!议 常见问题 1、DHT11是什么 &#xff1f;有什么特性 &#xff1f; 2、单总线协议是什么 &#xff1f;原理 &#xff1f;DHT11的单总线协议的组成 &#xff1f; ## 1、DHT11定义 单总线协议是一种用于在多个设备之间进行通信的协议&#xff0c;所有…...

Redisson分布式锁的概念和使用

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

uniapp小程序持续获取用户位置信息,后台位置获取

做一个小程序持续获取用户位置信息的功能&#xff0c;即使小程序切换到后台也能继续获取&#xff0c;getLocation这个api只有小程序在前台才能获取位置&#xff0c;所以不用这个 先申请一个腾讯地图key 在uniapp项目配置源码视图里加上这个代码 先获取权限&#xff0c;再开启…...

stm32G473的flash模式是单bank还是双bank?

今天突然有人stm32G473的flash模式是单bank还是双bank&#xff1f;由于时间太久&#xff0c;我真忘记了。搜搜发现&#xff0c;还真有人和我一样。见下面的链接&#xff1a;https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

P3 QT项目----记事本(3.8)

3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

AI编程--插件对比分析:CodeRider、GitHub Copilot及其他

AI编程插件对比分析&#xff1a;CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展&#xff0c;AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者&#xff0c;分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

HashMap中的put方法执行流程(流程图)

1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中&#xff0c;其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下&#xff1a; 初始判断与哈希计算&#xff1a; 首先&#xff0c;putVal 方法会检查当前的 table&#xff08;也就…...

uniapp 字符包含的相关方法

在uniapp中&#xff0c;如果你想检查一个字符串是否包含另一个子字符串&#xff0c;你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的&#xff0c;但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...