# 鸿蒙 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 期,更多内容请关注专栏。