Flutter for OpenHarmony Web开发助手App实战:密码生成器
圈型预测是游戏中的关键技能。提前知道安全区的位置能帮助玩家做出更好的决策。今天我们来实现一个圈型预测工具。
·

强密码是账户安全的第一道防线。下面这篇实战内容基于真实项目代码拆解实现思路:页面结构、交互配置、密码生成逻辑、强度提示和复制反馈。为了便于阅读,代码分成多个小片段,并在每段后面给出说明。
依赖与页面入口
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
说明
Random.secure()用于生成不可预测的随机序列。flutter_screenutil让 UI 在多尺寸下保持一致比例。Get.snackbar是实际项目里常用的轻量反馈方式。
class PasswordGeneratorPage extends StatefulWidget {
const PasswordGeneratorPage({Key? key}) : super(key: key);
State<PasswordGeneratorPage> createState() => _PasswordGeneratorPageState();
}
说明
- 这里用
StatefulWidget,是因为页面需要实时响应用户的滑块和勾选项。
页面状态与初始化
class _PasswordGeneratorPageState extends State<PasswordGeneratorPage> {
String _password = '';
double _length = 16;
bool _includeUppercase = true;
bool _includeLowercase = true;
bool _includeNumbers = true;
bool _includeSymbols = true;
final _random = Random.secure();
说明
- 默认长度设为 16,既能兼顾强度也不至于过长。
- 通过布尔开关控制字符类型组合,便于后续扩展。
void initState() {
super.initState();
_generatePassword();
}
说明
- 进入页面立刻生成一次密码,避免首次展示为空。
密码展示与基础操作
页面结构先保持简单,真实项目里通常会先把主卡片搭出来,再逐步补齐按钮和配置区块。
appBar: AppBar(title: const Text('密码生成器')),
body: SingleChildScrollView(
padding: EdgeInsets.all(16.w),
child: Column(
children: [
Card(
elevation: 4,
child: Padding(
padding: EdgeInsets.all(20.w),
child: Column(
children: [
Text('生成的密码', style: TextStyle(fontSize: 14.sp, color: Colors.grey[600])),
],
),
),
),
],
),
),
说明
- 先用
Card做视觉聚焦,后续内容会继续往里填。 SingleChildScrollView避免小屏内容溢出。
SelectableText(
_password,
style: TextStyle(fontSize: 24.sp, fontWeight: FontWeight.bold, fontFamily: 'monospace'),
textAlign: TextAlign.center,
),
说明
SelectableText支持用户长按选择复制,体验更贴近桌面端。- 使用等宽字体能让口令更易读,尤其是相似字符较多时。
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton.icon(
onPressed: _generatePassword,
icon: const Icon(Icons.refresh),
label: const Text('重新生成'),
),
SizedBox(width: 12.w),
OutlinedButton.icon(
onPressed: _copyPassword,
icon: const Icon(Icons.copy),
label: const Text('复制'),
),
],
),
说明
- 重新生成和复制是高频操作,放在同一行保证触达性。
- 使用
OutlinedButton区分主/次操作,避免视觉负担。 - 按钮图标采用系统图标,和平台风格一致。
长度与字符类型配置
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('密码长度', style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.bold)),
Text('${_length.toInt()} 位', style: TextStyle(fontSize: 18.sp, fontWeight: FontWeight.bold, color: Colors.blue)),
],
),
说明
- 右侧实时显示长度,用户不需要猜测当前值。
Slider(
value: _length,
min: 6,
max: 32,
divisions: 26,
onChanged: (value) {
setState(() {
_length = value;
_generatePassword();
});
},
),
说明
- 拖动滑块即时刷新密码,给用户“实时反馈”的感觉。
- 长度范围 6~32 对常见业务场景足够友好。
CheckboxListTile(
title: const Text('大写字母 (A-Z)'),
value: _includeUppercase,
onChanged: (v) {
setState(() {
_includeUppercase = v ?? true;
_generatePassword();
});
},
),
说明
- 每次勾选变化都触发重新生成,避免出现“配置生效不及时”的错觉。
CheckboxListTile(
title: const Text('小写字母 (a-z)'),
value: _includeLowercase,
onChanged: (v) {
setState(() {
_includeLowercase = v ?? true;
_generatePassword();
});
},
),
说明
- 小写字母默认开启,符合大部分业务默认配置。
CheckboxListTile(
title: const Text('数字 (0-9)'),
value: _includeNumbers,
onChanged: (v) {
setState(() {
_includeNumbers = v ?? true;
_generatePassword();
});
},
),
说明
- 数字是多数平台的硬性要求,所以放在中间更容易被注意到。
CheckboxListTile(
title: const Text('特殊符号 (!@#\$%^&*)'),
value: _includeSymbols,
onChanged: (v) {
setState(() {
_includeSymbols = v ?? true;
_generatePassword();
});
},
),
说明
- 保留一组常见符号,避免部分系统不支持过于复杂的字符。
密码强度反馈
强度提示是产品经理最常问的功能之一,这里做成了一个轻量的进度条,让用户一眼就能判断风险。
Widget _buildStrengthIndicator() {
final strength = _calculateStrength();
Color color;
String label;
说明
- 先算出强度值,再把颜色和文案准备好,后面渲染会更顺。
if (strength < 30) {
color = Colors.red;
label = '弱';
} else if (strength < 60) {
color = Colors.orange;
label = '中等';
} else if (strength < 80) {
color = Colors.blue;
label = '强';
} else {
color = Colors.green;
label = '非常强';
}
说明
- 强度阈值使用简单分段,便于在真实项目中快速解释给产品或测试。
return Column(
children: [
Row(
children: [
Expanded(
child: LinearProgressIndicator(
value: strength / 100,
backgroundColor: Colors.grey[200],
color: color,
minHeight: 8.h,
),
),
SizedBox(width: 12.w),
Text(label, style: TextStyle(fontSize: 14.sp, fontWeight: FontWeight.bold, color: color)),
],
),
说明
- 进度条在左,文本提示在右,布局更符合移动端阅读习惯。
SizedBox(height: 8.h),
Text('强度: ${strength.toInt()}%', style: TextStyle(fontSize: 12.sp, color: Colors.grey[600])),
],
);
说明
- 进度条 + 标签 + 数字三层信息,用户想要的细节都能覆盖。
double _calculateStrength() {
double strength = 0;
strength += (_length / 32) * 40;
说明
- 长度占 40% 权重,长度拉开后强度变化更明显。
int types = 0;
if (_includeUppercase) types++;
if (_includeLowercase) types++;
if (_includeNumbers) types++;
if (_includeSymbols) types++;
strength += (types / 4) * 60;
return strength.clamp(0, 100);
}
说明
- 评分拆为“长度权重 + 字符多样性权重”,逻辑清晰且便于调整。
生成与复制逻辑
void _generatePassword() {
String chars = '';
if (_includeUppercase) chars += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
if (_includeLowercase) chars += 'abcdefghijklmnopqrstuvwxyz';
if (_includeNumbers) chars += '0123456789';
if (_includeSymbols) chars += '!@#\$%^&*()_+-=[]{}|;:,.<>?';
说明
- 先拼出可用字符池,后面只需要做随机抽取即可。
if (chars.isEmpty) {
setState(() => _password = '请至少选择一种字符类型');
return;
}
说明
- 优先处理“空字符集”这一真实场景,避免异常或空输出。
setState(() {
_password = List.generate(
_length.toInt(),
(index) => chars[_random.nextInt(chars.length)],
).join();
});
}
说明
List.generate+Random.secure()组合能保证随机性和性能。
void _copyPassword() {
Clipboard.setData(ClipboardData(text: _password));
Get.snackbar('成功', '密码已复制', snackPosition: SnackPosition.BOTTOM, duration: const Duration(seconds: 2));
}
说明
- 复制后立即弹出反馈,比静默成功更符合真实产品习惯。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐



所有评论(0)