# 鸿蒙 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 阶段
- 密码同时保存在
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 期,更多内容请关注专栏。
更多推荐


所有评论(0)