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

# 鸿蒙 HarmonyOS 应用开发实战(第38期)|密码锁(Password Lock)— Grid 网格键盘与四阶段状态机

一、应用概述

密码锁(Password Lock)是一款模拟数字密码锁的应用。它模拟了真实密码锁的完整操作流程:设置密码 → 确认密码 → 解锁验证 → 错误锁定。用户通过数字键盘输入 4 位密码,系统根据当前阶段执行不同逻辑,错误次数超过 5 次后触发 5 秒锁定机制。

从技术角度看,这是系列教程中状态机设计最为复杂的一个应用。它包含四个明确的阶段(set/confirm/unlock/locked),每个阶段对用户输入的响应完全不同。此外,应用还引入了Grid网格布局构建数字键盘、Circle组件作为密码点显示、setTimeout一次性定时器等功能,是状态管理和布局设计的集大成者。

二、技术架构与组件树

2.1 整体架构

@Entry @Component struct index38 ├── Column (根容器) │ ├── Row (顶部导航栏) │ └── Column (主内容区, 居中) │ ├── Text (提示消息, 颜色动态变化) │ ├── Row (密码点, 4个 Circle) │ │ └── ForEach → Circle × 4 │ ├── Grid (数字键盘, columnsTemplate="1fr 1fr 1fr") │ │ ├── GridItem × 9 ("1" ~ "9") │ │ ├── GridItem ("") │ │ ├── GridItem ("0") │ │ └── GridItem ("⌫" 删除键) │ └── Button ("🔄 重置")

2.2 状态变量设计

@State password: string = ''; // 当前输入的密码 @State savedPassword: string = '1234'; // 已保存的密码 @State stage: 'set' | 'confirm' | 'unlock' | 'locked' = 'set'; @State confirmPassword: string = ''; // 确认阶段暂存的密码 @State message: string = '设置4位数字密码'; @State attempts: number = 0; // 错误尝试次数 @State locked: boolean = false; // 是否锁定 lockTimer: number = -1; // 锁定定时器 ID

联合类型状态stage使用了 TypeScript/ArkTS 的字符串联合类型'set' | 'confirm' | 'unlock' | 'locked'),将变量的取值范围限制在四个预定义字符串中。这种类型约束可以在编译阶段捕获拼写错误。

三、核心代码深度解析

3.1 四阶段状态机

┌──────────┐ │ set (设置) │ └─────┬────┘ │ 输入4位密码 ▼ ┌──────────┐ │confirm(确认)│ └─────┬────┘ ┌───┴───┐ │ │ 匹配 │ │ 不匹配 │ │ ▼ ▼ ┌────────┐ ┌──────────┐ │ unlock │ │set (重新) │ │ (解锁) │ └──────────┘ └──┬─────┘ ┌───┴───┐ │ │ 正确 │ │ 错误(≥5次) │ │ ▼ ▼ ┌─────────┐ ┌────────┐ │解锁成功 │ │ locked │ └─────────┘ │(锁定5s)│ └────────┘

这个状态机是密码锁的核心逻辑。pressNum函数根据当前stage执行不同的分支:

pressNum(n: string) { if (this.locked) return; if (this.password.length >= 4) return; this.password += n; if (this.password.length === 4) { if (this.stage === 'set') { // 阶段1:设置密码 this.savedPassword = this.password; this.confirmPassword = this.password; this.stage = 'confirm'; this.message = '请再次输入确认'; this.password = ''; } else if (this.stage === 'confirm') { // 阶段2:确认密码 if (this.password === this.confirmPassword) { this.stage = 'unlock'; this.message = '✅ 密码设置成功!试试解锁'; this.savedPassword = this.confirmPassword; } else { this.message = '❌ 两次密码不一致,重新设置'; this.stage = 'set'; } this.password = ''; } else if (this.stage === 'unlock') { // 阶段3:解锁验证 if (this.password === this.savedPassword) { this.message = '🔓 解锁成功!'; this.locked = false; } else { this.attempts++; this.message = `❌ 密码错误 (${this.attempts}/5)`; if (this.attempts >= 5) { // 阶段4:锁定 this.locked = true; this.message = '🔒 尝试次数过多,已锁定'; this.lockTimer = setTimeout(() => { this.locked = false; this.attempts = 0; this.message = '可以重新尝试'; }, 5000); } } this.password = ''; } } }

每个阶段的分析

阶段 set(设置密码)

  • 输入 4 位数字后自动进入 confirm 阶段
  • 密码同时保存在savedPasswordconfirmPassword

阶段 confirm(确认密码)

  • 再次输入 4 位密码
  • confirmPassword比对
  • 匹配 → 进入 unlock 阶段,显示成功消息
  • 不匹配 → 回到 set 阶段重新设置,显示错误消息

阶段 unlock(解锁验证)

  • 输入 4 位密码与savedPassword比对
  • 正确 → 解锁成功(locked = false
  • 错误 →attempts++,达到 5 次进入 locked 阶段

阶段 locked(锁定)

  • locked = true,输入被阻止(if (this.locked) return
  • setTimeout5 秒后自动解锁
  • 解锁后恢复可输入状态,attempts归零

3.2 密码点显示

Row({ space: 12 }) { ForEach([0, 1, 2, 3], (i: number) => { Circle() .width(16).height(16) .fill(this.password.length > i ? '#333' : '#ddd') .stroke('#bbb').strokeWidth(1) }) }.margin({ bottom: 24 })

四个Circle圆形代表四位密码的输入状态:

  • 已输入password.length > i):填充深色 #333
  • 未输入password.length <= i):填充浅色 #ddd

这种「圆点填充」的密码视觉反馈是行业标准做法——既让用户知道已输入了几位数字,又不会泄露密码内容。

3.3 Grid 网格数字键盘

Grid() { ForEach(['1', '2', '3', '4', '5', '6', '7', '8', '9', '', '0', '⌫'], (n: string, idx: number) => { GridItem() { if (n === '⌫') { Text('⌫').fontSize(28).fontColor('#F44336') .width('100%').height(60).textAlign(TextAlign.Center) .onClick(() => this.delete()) } else if (n === '') { Text('') } else { Text(n).fontSize(28).fontWeight(FontWeight.Bold) .width('100%').height(60).textAlign(TextAlign.Center) .onClick(() => this.pressNum(n)) } } }) } .columnsTemplate('1fr 1fr 1fr') .rowsTemplate('60px 60px 60px 60px') .width(240).rowsGap(4).columnsGap(4)

Grid 关键属性

属性说明
columnsTemplate'1fr 1fr 1fr'三列等宽布局
rowsTemplate'60px 60px 60px 60px'四行,每行 60px
rowsGap4行间距 4px
columnsGap4列间距 4px

'1fr'是 Grid 布局中的弹性系数,表示将可用空间按比例分配。'1fr 1fr 1fr'就是三等分。

键盘布局:12 个 GridItem 排成 4 行 × 3 列:

1 2 3 4 5 6 7 8 9 0 ⌫

第 4 行第一个位置(索引 9)是空字符串,用于占位,因为标准数字键盘是 3×4 布局,左下角通常是空位或符号键。

删除键使用红色(#F44336)与数字键区分,点击触发delete()方法:

delete() { this.password = this.password.slice(0, -1); }

使用slice(0, -1)删除字符串的最后一个字符,实现退格功能。

3.4 重置功能

reset() { clearTimeout(this.lockTimer); this.password = ''; this.stage = 'set'; this.attempts = 0; this.locked = false; this.message = '设置4位数字密码'; }

重置将应用恢复到最初始的状态(set 阶段)。注意clearTimeout(this.lockTimer)清除锁定定时器——如果用户在被锁定时点击重置,应该立即解除锁定。

四、HarmonyOS 特性分析

4.1 Grid 网格布局 vs 其他布局

布局适用场景本例使用
Column/Row线性排列顶部导航、主框架
Stack层叠重叠未使用(密码锁不需要重叠)
Grid二维网格数字键盘
List滚动列表未使用

Grid是最适合键盘布局的容器。相比用Column+ 多个Row模拟网格,GridcolumnsTemplate+rowsTemplate可以精确控制行列分布,代码也更简洁。

4.2 setTimeout 一次性定时器

this.lockTimer = setTimeout(() => { this.locked = false; this.attempts = 0; this.message = '可以重新尝试'; }, 5000);

setInterval(周期性执行)不同,setTimeout只在指定延迟后执行一次。它非常适合:

  • 延迟操作:密码锁的定时解锁
  • 动画序列:先 A 动画,500ms 后 B 动画
  • 防抖:用户停止输入 300ms 后再搜索

同样需要在aboutToDisappearresetclearTimeout清理。

4.3 Circle 组件作为状态指示器

密码锁使用 4 个Circle作为密码输入指示器,这与第 31 期模拟时钟使用Circle作为表盘和中心点的用法不同。同一个组件在不同场景中扮演不同角色,体现了 ArkTS 组件系统的高度灵活性。

五、UI/UX 设计与最佳实践

5.1 消息提示的动态颜色

Text(this.message).fontSize(16) .fontColor( this.message.includes('✅') ? '#4CAF50' : this.message.includes('❌') ? '#F44336' : '#666')

消息文字的颜色根据内容自动变化:

  • 包含 ✅ → 绿色(成功)
  • 包含 ❌ → 红色(失败)
  • 其他 → 灰色(中性)

这种「内容驱动颜色」的模式,无需为每种消息单独设置颜色变量,简洁且不易出错。

5.2 锁定状态的视觉反馈

locked = true时:

  1. 所有按键操作被阻止(if (this.locked) return
  2. 消息显示锁定提示
  3. 用户点击任何数字键都无响应

这种「软禁用」比隐藏键盘更合适——用户看到键盘但不能操作,明白系统处于锁定状态。

5.3 用户体验流程

设置密码 → 确认密码 → 解锁验证 → (错误 5 次)→ 锁定 → 自动解锁

这个流程模拟了真实设备上设置和解锁密码的完整体验,让用户在一个页面内完成所有操作,无需跳转。

六、可扩展思路

  1. 更长的密码:支持 4-8 位可变长度密码。
  2. 生物识别:集成指纹或面部识别(@ohos.userIAM.userAuth)作为解锁方式。
  3. 安全键盘:每次打开键盘时随机排列数字键顺序,防止偷窥。
  4. 应用锁整合:将密码锁作为应用锁,保护其他应用的安全。
  5. 密码找回:设置安全问题或备用邮箱用于密码找回。

七、总结

密码锁应用以 124 行代码,实现了一个包含四阶段状态机的完整密码管理系统。它的技术亮点包括:

  • 联合类型状态机'set' | 'confirm' | 'unlock' | 'locked'精确控制应用状态
  • Grid 网格键盘columnsTemplate+rowsTemplate构建标准数字键盘
  • Circle 密码指示器:圆点填充状态反映密码输入进度
  • setTimeout 锁定机制:5 次错误后自动锁定 5 秒
  • 动态消息颜色:根据消息内容自动匹配颜色
  • slice 删除:字符串退格操作的简洁实现

这个应用的状态机架构是整个系列的亮点——四个阶段、每个阶段对输入的不同响应、错误阈值、定时解锁——这些概念可以直接应用于登录页面、支付验证、权限控制等真实场景。

下一期我们将从安全领域转向创意表达,探讨一个充满趣味性的应用——手势绘制(Drawing Canvas),看如何用 onTouch 事件构建涂鸦画板。


本文是 HarmonyOS 应用开发实战系列第 38 期,更多内容请关注专栏。

http://www.jsqmd.com/news/1291191/

相关文章:

  • vasp_raman.py 拉曼活性计算:3个步骤快速掌握VASP材料光谱分析
  • 基于机器学习的重庆市房价预测分析研究31234(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_
  • 2027 年纽约实施《儿童安全法案》:社交媒体算法推荐、午夜通知将设年龄验证
  • Agent 工作流重放与断点续传:失败任务不必从头跑(续篇)
  • 【GitHub】Bend:让 GPU 并行编程像写 Python 一样简单
  • Java开发环境搭建全攻略:从JDK安装、环境变量配置到多版本管理
  • R语言生信分析环境搭建:从CRAN、Bioconductor到GitHub的完整部署指南
  • Python图像批处理实战:从Pillow基础到21张图片批量优化
  • 2024年广东省职业院校技能大赛(高职组)大数据应用开发第05套完整参考答案
  • GJK算法实战:从原理到Unity/Unreal碰撞检测实现
  • 终极暗黑破坏神2高清补丁:D2DX三步安装教程与画质革命
  • AI康复训练指导如何精准匹配患者?揭秘FDA认证算法背后的3层动态适配机制
  • CI 中的测试策略分层:smoke、integration 与 e2e 的执行时机
  • 从A.dx到数值积分:工程实践中的微积分核心操作指南
  • # HarmonyOS ArkTS 小游戏开发实战(一):弹弹球物理碰撞游戏
  • STM32智能小车实战:从硬件选型到PID算法,手把手教你打造循迹机器人
  • 智能车图像处理:八邻域边界追踪与中心线提取实战指南
  • STM32主从定时器实现任意相位差PWM输出配置详解
  • 揭秘司法AI法条推荐准确率提升47%的关键:从语义理解到动态权重建模全流程拆解
  • Web安全核心:从数据流视角剖析SQL注入、反序列化与文件上传漏洞
  • 收到学术不端指控邮件后,千万别急着做这三件事——附英澳真实听证会案例
  • 2026年近期惠州五金外壳找哪家?5大优选厂商深度盘点 - 装修教育财税推荐2026
  • 2026AI智能纪要助力培训效果评估 准识别快整理更清晰更省事
  • 流批安卓自动点击神器,轻松搞定重复操作
  • Avatar骨骼映射:用大白话讲清楚这件事
  • 最新量化开发分阶段,工具和AI代码都要放对位置
  • 飞致云发布1Panel AI一体机产品家族
  • 从NPC台词到史诗终章:手把手教你用Diffusion+GraphRAG构建动态剧情树(含可商用许可清单)
  • Python第四次作业:从基础语法到实战项目全解析
  • 如何通过智能自动化工具提升英雄联盟游戏体验:League Akari完整指南