一、应用概述
密码锁(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 阶段
- 密码同时保存在
savedPassword和confirmPassword中
阶段 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 |
rowsGap | 4 | 行间距 4px |
columnsGap | 4 | 列间距 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模拟网格,Grid的columnsTemplate+rowsTemplate可以精确控制行列分布,代码也更简洁。
4.2 setTimeout 一次性定时器
this.lockTimer = setTimeout(() => { this.locked = false; this.attempts = 0; this.message = '可以重新尝试'; }, 5000);与setInterval(周期性执行)不同,setTimeout只在指定延迟后执行一次。它非常适合:
- 延迟操作:密码锁的定时解锁
- 动画序列:先 A 动画,500ms 后 B 动画
- 防抖:用户停止输入 300ms 后再搜索
同样需要在aboutToDisappear或reset中clearTimeout清理。
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时:
- 所有按键操作被阻止(
if (this.locked) return) - 消息显示锁定提示
- 用户点击任何数字键都无响应
这种「软禁用」比隐藏键盘更合适——用户看到键盘但不能操作,明白系统处于锁定状态。
5.3 用户体验流程
设置密码 → 确认密码 → 解锁验证 → (错误 5 次)→ 锁定 → 自动解锁
这个流程模拟了真实设备上设置和解锁密码的完整体验,让用户在一个页面内完成所有操作,无需跳转。
六、可扩展思路
- 更长的密码:支持 4-8 位可变长度密码。
- 生物识别:集成指纹或面部识别(
@ohos.userIAM.userAuth)作为解锁方式。 - 安全键盘:每次打开键盘时随机排列数字键顺序,防止偷窥。
- 应用锁整合:将密码锁作为应用锁,保护其他应用的安全。
- 密码找回:设置安全问题或备用邮箱用于密码找回。
七、总结
密码锁应用以 124 行代码,实现了一个包含四阶段状态机的完整密码管理系统。它的技术亮点包括:
- 联合类型状态机:
'set' | 'confirm' | 'unlock' | 'locked'精确控制应用状态 - Grid 网格键盘:
columnsTemplate+rowsTemplate构建标准数字键盘 - Circle 密码指示器:圆点填充状态反映密码输入进度
- setTimeout 锁定机制:5 次错误后自动锁定 5 秒
- 动态消息颜色:根据消息内容自动匹配颜色
- slice 删除:字符串退格操作的简洁实现
这个应用的状态机架构是整个系列的亮点——四个阶段、每个阶段对输入的不同响应、错误阈值、定时解锁——这些概念可以直接应用于登录页面、支付验证、权限控制等真实场景。
下一期我们将从安全领域转向创意表达,探讨一个充满趣味性的应用——手势绘制(Drawing Canvas),看如何用 onTouch 事件构建涂鸦画板。
本文是 HarmonyOS 应用开发实战系列第 38 期,更多内容请关注专栏。