Flutter三方库适配OpenHarmony【random_number】随机数生成器项目完整实战
前言
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
random_number 是一个基于 Flutter 的随机数生成器项目,核心代码位于 lib/main.dart。它通过两个输入框接收最小值和最大值,点击按钮后生成指定范围内的随机整数,并使用短暂的滚动数字效果增强反馈。最终结果会展示在渐变卡片中,最近生成过的数字会以 Chip 形式保存在历史记录区域。
这个项目适合用来讲解 Flutter 在 OpenHarmony 上的基础表单交互、数字输入解析、范围校验、异步状态刷新、随机数生成、历史记录维护和 Material 组件渲染。它没有复杂插件依赖,问题定位集中,非常适合做跨平台适配入门案例。

图片说明:本文基于 Flutter 表单、状态管理和 OpenHarmony 承载工程展开,随机数生成逻辑来自 random_number 的真实源码。
随机数生成器的核心不只是
Random().nextInt(),还包括输入容错、范围边界、异步刷新、历史记录和跨端 UI 表现。
一、项目背景与目标
1.1 项目定位
random_number 是一个轻量工具类应用。用户输入最小值和最大值,点击按钮后,应用在该闭区间内生成随机整数。例如默认范围是 1 到 100,结果可能是 1、100 或中间任意整数。
当前项目真实支持的功能包括:
- 默认最小值为
1。 - 默认最大值为
100。 - 通过两个
TextField输入范围。 - 使用
int.tryParse安全解析输入。 - 当最小值大于最大值时显示
SnackBar。 - 点击按钮后进入
Rolling...状态。 - 通过 20 次延迟刷新模拟滚动数字。
- 1 秒后生成最终随机结果。
- 将最终结果插入历史记录顶部。
- 历史记录最多保留 10 条。
- 使用
Wrap和Chip展示历史记录。
1.2 技术目标
本文围绕真实源码拆解以下技术点:
- Flutter 应用入口和 Material 3 主题配置。
TextEditingController如何管理输入框默认值。int.tryParse如何避免输入解析异常。SnackBar如何提示范围错误。math.Random().nextInt()如何生成闭区间随机数。Future.delayed如何模拟滚动数字效果。mounted如何保护异步回调中的setState。List<int>如何维护最多 10 条历史记录。Wrap + Chip如何展示动态历史数据。- OpenHarmony 侧如何验证输入、滚动、结果和历史展示。
1.3 核心实现速览
| 能力 | 当前实现 | 适配关注点 |
|---|---|---|
| 应用入口 | runApp(const RandomNumberApp()) |
确认首帧正常渲染 |
| 主题 | ColorScheme.fromSeed(seedColor: Colors.purple) |
确认紫色主题和 Material 3 样式 |
| 输入 | 两个 TextField |
确认软键盘、输入框、焦点状态 |
| 解析 | int.tryParse |
确认非法输入有默认兜底 |
| 校验 | min > max 时显示 SnackBar |
确认错误提示展示 |
| 随机数 | min + Random().nextInt(max - min + 1) |
确认结果落在闭区间 |
| 滚动效果 | 20 个延迟任务刷新结果 | 确认异步刷新稳定 |
| 历史记录 | _history.insert(0, finalResult) |
确认最新结果置顶 |
| 历史上限 | 超过 10 条删除末尾 | 确认历史数量稳定 |
二、环境准备与工程结构
2.1 工程结构
项目保持 Flutter 标准结构,同时包含 OpenHarmony 平台工程目录。
| 文件或目录 | 作用 |
|---|---|
lib/main.dart |
应用入口、输入框、随机逻辑、结果卡片和历史记录 |
pubspec.yaml |
SDK 约束、Flutter 依赖和资源配置 |
analysis_options.yaml |
Dart 静态分析规则 |
test/ |
Flutter 测试目录 |
ohos/ |
OpenHarmony 平台承载工程 |
README.md |
项目说明文件 |
lib/main.dart 是本文的核心,当前项目所有业务逻辑都在这个文件中完成。
2.2 依赖配置
项目使用 Dart SDK ^3.9.2,业务实现依赖 Flutter SDK 和 Dart 标准库。
yaml
environment:
sdk: ^3.9.2
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.8
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^5.0.0
flutter:
uses-material-design: true
随机数生成来自 dart:math,输入、按钮、卡片、图标和提示组件来自 Flutter Material。
2.3 常用命令
bash
flutter pub get
flutter analyze
flutter test
flutter run
| 命令 | 用途 |
|---|---|
flutter pub get |
获取依赖 |
flutter analyze |
静态分析 Dart 代码 |
flutter test |
执行测试 |
flutter run |
在目标设备运行 |
OpenHarmony 工程中还需要结合本地 Flutter OpenHarmony 工具链完成 HAP 构建和设备运行。
三、应用入口与主题配置
3.1 main 函数
项目入口很简洁:
dart
import 'package:flutter/material.dart';
import 'dart:math' as math;
void main() {
runApp(const RandomNumberApp());
}
material.dart 提供页面、输入框、按钮、卡片、图标、SnackBar 和布局组件。dart:math as math 用于生成随机数。
3.2 RandomNumberApp
根组件负责创建 MaterialApp。
dart
class RandomNumberApp extends StatelessWidget {
const RandomNumberApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Random Number',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.purple),
useMaterial3: true,
),
home: const RandomNumberHomePage(title: 'Random Number'),
);
}
}
这段代码包含三个关键点:
title设置应用标题。ColorScheme.fromSeed使用紫色生成主题色。home指向随机数生成页面。
3.3 OpenHarmony 首屏验证
OpenHarmony 上运行时,首屏需要确认:
- AppBar 显示
Random Number。 - 两个输入框默认值分别为
1和100。 - 结果卡片初始显示
?。 - 按钮显示
Generate Random Number。 - 未生成结果前不显示历史记录区域。
如果首屏异常,优先检查 Flutter 页面是否被 OpenHarmony entry 模块正确承载。
四、页面状态设计
4.1 StatefulWidget
随机数生成器需要记录输入、结果、滚动状态和历史,因此页面使用 StatefulWidget。
dart
class RandomNumberHomePage extends StatefulWidget {
const RandomNumberHomePage({super.key, required this.title});
final String title;
@override
State<RandomNumberHomePage> createState() => _RandomNumberHomePageState();
}
title 用于 AppBar。状态由 _RandomNumberHomePageState 管理。
4.2 状态字段
dart
class _RandomNumberHomePageState extends State<RandomNumberHomePage> {
final TextEditingController _minController = TextEditingController(text: '1');
final TextEditingController _maxController = TextEditingController(text: '100');
int? _result;
bool _isRolling = false;
final List<int> _history = [];
}
| 字段 | 类型 | 初始值 | 作用 |
|---|---|---|---|
_minController |
TextEditingController |
1 |
管理最小值输入 |
_maxController |
TextEditingController |
100 |
管理最大值输入 |
_result |
int? |
null |
当前结果,空值时显示 ? |
_isRolling |
bool |
false |
标记是否正在滚动 |
_history |
List<int> |
空列表 | 保存最近结果 |
4.3 状态关系
_result、_isRolling 和 _history 分别控制三个界面区域:
_result控制结果卡片显示?还是具体数字。_isRolling控制结果状态文字和数字颜色。_history控制历史记录区域是否展示,以及展示哪些Chip。
对表单工具类应用来说,状态字段要尽量少而明确。当前代码把输入、结果、状态和历史分开维护,阅读成本较低。
五、范围输入实现
5.1 输入区域布局
页面顶部用 Row 放置两个输入框。
dart
Row(
children: [
Expanded(
child: TextField(
controller: _minController,
keyboardType: TextInputType.number,
decoration: InputDecoration(
labelText: 'Min',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
filled: true,
),
),
),
const SizedBox(width: 16),
Expanded(
child: TextField(
controller: _maxController,
keyboardType: TextInputType.number,
decoration: InputDecoration(
labelText: 'Max',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
filled: true,
),
),
),
],
)
两个 Expanded 让输入框平分横向空间,中间使用 SizedBox 保持间距。
5.2 数字键盘
输入框设置了数字键盘:
dart
keyboardType: TextInputType.number
这可以让移动端优先弹出数字输入键盘。OpenHarmony 侧需要确认软键盘弹出、输入焦点和页面滚动表现。
5.3 输入框样式
输入框使用圆角边框和填充背景:
dart
decoration: InputDecoration(
labelText: 'Min',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
filled: true,
)
labelText 分别为 Min 和 Max,用户能清楚区分两个输入框的含义。
六、输入解析与范围校验
6.1 安全解析整数
生成随机数前,代码先读取并解析输入框内容。
dart
final min = int.tryParse(_minController.text) ?? 1;
final max = int.tryParse(_maxController.text) ?? 100;
int.tryParse 解析失败时返回 null。代码使用 ?? 提供默认值,最小值默认 1,最大值默认 100。
6.2 范围校验
当最小值大于最大值时,代码通过 SnackBar 提示错误并结束方法。
dart
if (min > max) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Minimum must be less than maximum')),
);
return;
}
这段逻辑避免调用 nextInt 时出现非法范围。
6.3 校验场景
| 输入 Min | 输入 Max | 解析结果 | 页面表现 |
|---|---|---|---|
1 |
100 |
min=1, max=100 | 正常生成 |
50 |
50 |
min=50, max=50 | 结果恒为 50 |
100 |
1 |
min=100, max=1 | 显示 SnackBar |
| 空字符串 | 空字符串 | min=1, max=100 | 使用默认范围 |
| 非数字 | 非数字 | min=1, max=100 | 使用默认范围 |
当前代码没有限制负数输入。如果平台键盘允许输入负号,公式仍然可以生成负数范围内的随机整数。
七、随机数生成逻辑
7.1 闭区间公式
项目使用下面的公式生成结果:
dart
min + math.Random().nextInt(max - min + 1)
nextInt(n) 的结果范围是 0 <= value < n。因此 max - min + 1 可以覆盖闭区间 [min, max]。
7.2 示例推导
以默认范围 1 到 100 为例:
dart
final value = 1 + math.Random().nextInt(100 - 1 + 1);
nextInt(100) 返回 0 到 99,加上 1 后得到 1 到 100。
7.3 边界值
| 范围 | nextInt 参数 |
可能结果 |
|---|---|---|
| 1 到 100 | 100 |
1 到 100 |
| 0 到 9 | 10 |
0 到 9 |
| 10 到 10 | 1 |
10 |
| -5 到 5 | 11 |
-5 到 5 |
这个公式是随机整数工具中最常用的闭区间写法。
八、滚动数字效果
8.1 进入滚动状态
点击按钮后,代码先设置 _isRolling = true。
dart
setState(() {
_isRolling = true;
});
页面随后显示 Rolling...,结果数字颜色变为灰色。
8.2 20 次延迟刷新
滚动效果通过循环创建 20 个延迟任务实现。
dart
for (int i = 0; i < 20; i++) {
Future.delayed(Duration(milliseconds: 50 * i), () {
if (mounted) {
setState(() {
_result = min + math.Random().nextInt(max - min + 1);
});
}
});
}
每隔 50 毫秒刷新一次临时结果,20 次刚好持续约 1 秒。用户看到的是数字快速变化的过程。
8.3 mounted 保护
循环中的异步回调使用了 mounted 判断。
dart
if (mounted) {
setState(() {
_result = min + math.Random().nextInt(max - min + 1);
});
}
如果页面已经销毁,mounted 为 false,代码不会继续调用 setState。这是异步 UI 更新中非常重要的保护。
异步延迟和页面生命周期经常同时出现。只要回调里会调用
setState,就应该考虑页面是否仍然挂载。
九、最终结果与历史记录
9.1 最终结果生成
1 秒后,项目生成最终随机数。
dart
Future.delayed(const Duration(milliseconds: 1000), () {
final random = math.Random();
final finalResult = min + random.nextInt(max - min + 1);
setState(() {
_result = finalResult;
_isRolling = false;
_history.insert(0, finalResult);
if (_history.length > 10) {
_history.removeLast();
}
});
});
最终结果会覆盖滚动过程中的临时结果。
9.2 历史记录置顶
dart
_history.insert(0, finalResult);
insert(0, value) 把最新结果放在列表头部。这样页面展示时,最新数字会排在最前面。
9.3 历史记录上限
dart
if (_history.length > 10) {
_history.removeLast();
}
历史记录超过 10 条时,删除最后一个元素。这样列表不会无限增长。
9.4 历史维护流程
| 步骤 | 操作 | 结果 |
|---|---|---|
| 1 | 生成最终随机数 | 得到 finalResult |
| 2 | 更新 _result |
结果卡片显示最终值 |
| 3 | 设置 _isRolling = false |
状态文字恢复为 Result |
| 4 | 插入 _history 头部 |
最新记录置顶 |
| 5 | 判断长度 | 超过 10 条删除最旧记录 |
十、结果卡片 UI
10.1 Card 容器
结果区域使用 Card 和渐变背景。
dart
Card(
elevation: 8,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
child: Container(
width: double.infinity,
padding: const EdgeInsets.all(48),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
gradient: LinearGradient(
colors: [Colors.purple.shade200, Colors.purple.shade100],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
),
)
卡片使用 double.infinity 占满横向宽度,padding: 48 给大号数字留出视觉空间。
10.2 结果数字
结果数字使用 80 号粗体。
dart
Text(
_result?.toString() ?? '?',
style: TextStyle(
fontSize: 80,
fontWeight: FontWeight.bold,
color: _isRolling ? Colors.grey : Colors.purple,
),
)
当 _result 为 null 时显示 ?。滚动过程中数字为灰色,结束后变为紫色。
10.3 状态文案
dart
Text(
_isRolling ? 'Rolling...' : 'Result',
style: TextStyle(
fontSize: 16,
color: Colors.purple.shade700,
),
)
Rolling... 和 Result 让用户知道当前处于生成中还是结果展示状态。
十一、按钮交互
11.1 ElevatedButton.icon
生成按钮使用图标加文字。
dart
ElevatedButton.icon(
onPressed: _generateRandom,
icon: const Icon(Icons.casino),
label: const Text('Generate Random Number'),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(16),
backgroundColor: Colors.purple,
minimumSize: const Size(double.infinity, 56),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
)
按钮宽度为 double.infinity,高度至少 56,适合移动端点击。
11.2 当前交互特点
当前按钮在滚动过程中仍然可以点击,因为代码没有把 onPressed 设置为 null。如果用户连续点击,会创建多组延迟任务,结果和历史可能快速变化。
可以基于 _isRolling 增加交互保护:
dart
ElevatedButton.icon(
onPressed: _isRolling ? null : _generateRandom,
icon: const Icon(Icons.casino),
label: Text(_isRolling ? 'Rolling...' : 'Generate Random Number'),
)
这类优化适合在更正式的工具应用中加入。
11.3 OpenHarmony 点击验证
| 场景 | 操作 | 预期 |
|---|---|---|
| 默认范围 | 点击按钮 | 生成 1 到 100 的数字 |
| 修改 Min | 输入 10 |
结果不小于 10 |
| 修改 Max | 输入 20 |
结果不大于 20 |
| 错误范围 | 输入 Min=20, Max=10 | 显示 SnackBar |
| 连续点击 | 快速点击按钮 | 数字和历史持续刷新 |
十二、历史记录展示
12.1 条件渲染
历史记录为空时不展示历史区域。
dart
if (_history.isNotEmpty) ...[
const SizedBox(height: 24),
const Text(
'History',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Wrap(
spacing: 8,
runSpacing: 8,
alignment: WrapAlignment.center,
children: _history.map((num) {
return Chip(
label: Text(num.toString()),
backgroundColor: Colors.purple.shade50,
);
}).toList(),
),
]
if (_history.isNotEmpty) ...[] 是 Flutter 中常见的集合展开写法,适合条件渲染多个 Widget。
12.2 Wrap 布局
历史数字使用 Wrap 展示。
dart
Wrap(
spacing: 8,
runSpacing: 8,
alignment: WrapAlignment.center,
children: _history.map((num) {
return Chip(
label: Text(num.toString()),
backgroundColor: Colors.purple.shade50,
);
}).toList(),
)
Wrap 会根据屏幕宽度自动换行,比横向 Row 更适合动态数量的历史记录。
12.3 Chip 组件
每条历史记录渲染为 Chip。
dart
Chip(
label: Text(num.toString()),
backgroundColor: Colors.purple.shade50,
)
Chip 的优点是视觉轻量、边界清晰,适合展示短文本标签。
十三、OpenHarmony 适配要点
13.1 表单输入
OpenHarmony 侧重点验证输入框能力:
- 点击输入框后软键盘是否弹出。
- 数字键盘是否符合
TextInputType.number。 - 输入内容是否能正确同步到
TextEditingController。 - AppBar、输入框、卡片和按钮在键盘弹出后是否仍可访问。
13.2 SnackBar 提示
范围错误时,SnackBar 由 ScaffoldMessenger 展示。
dart
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Minimum must be less than maximum')),
);
OpenHarmony 上需要确认 SnackBar 的位置、停留时间、文字颜色和页面遮挡情况。
13.3 异步刷新
滚动数字依赖多个 Future.delayed。
| 异步任务 | 作用 | 持续时间 |
|---|---|---|
| 20 次短延迟 | 模拟滚动数字 | 约 1 秒 |
| 1 次最终延迟 | 确认最终结果 | 1 秒 |
这类代码适合观察 OpenHarmony 上的定时任务、UI 刷新和页面生命周期。
13.4 滚动容器
页面根内容使用 SingleChildScrollView。
dart
body: SingleChildScrollView(
padding: const EdgeInsets.all(24.0),
child: Column(
children: [
// 输入、结果、按钮、历史
],
),
)
当屏幕较小或软键盘弹出时,滚动容器可以降低内容被遮挡的风险。
十四、测试与验证
14.1 初始页面测试
可以用 Widget 测试验证初始文案。
dart
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/material.dart';
void main() {
testWidgets('random number page shows initial widgets', (tester) async {
await tester.pumpWidget(const RandomNumberApp());
expect(find.text('Random Number'), findsWidgets);
expect(find.text('Min'), findsOneWidget);
expect(find.text('Max'), findsOneWidget);
expect(find.text('?'), findsOneWidget);
expect(find.text('Generate Random Number'), findsOneWidget);
});
}
这类测试不依赖随机结果,稳定性较高。
14.2 错误范围测试
错误范围可以验证 SnackBar。
dart
testWidgets('shows snackbar when min is greater than max', (tester) async {
await tester.pumpWidget(const RandomNumberApp());
await tester.enterText(find.widgetWithText(TextField, 'Min'), '10');
await tester.enterText(find.widgetWithText(TextField, 'Max'), '1');
await tester.tap(find.text('Generate Random Number'));
await tester.pump();
expect(find.text('Minimum must be less than maximum'), findsOneWidget);
});
该测试覆盖输入、校验和提示链路。
14.3 手工验证矩阵
| 验证项 | 操作 | 预期 |
|---|---|---|
| 初始状态 | 打开应用 | 显示默认输入、问号和按钮 |
| 正常生成 | 点击按钮 | 结果在范围内 |
| 错误范围 | Min 大于 Max | 显示 SnackBar |
| 相等范围 | Min 等于 Max | 结果恒等于该值 |
| 历史记录 | 连续生成 3 次 | 历史显示 3 个 Chip |
| 历史上限 | 连续生成超过 10 次 | 历史最多 10 条 |
| 小屏显示 | 缩小屏幕或弹出键盘 | 页面可滚动 |
十五、常见问题与优化建议
15.1 为什么使用 int.tryParse
用户输入不一定是合法数字。int.parse 遇到非法输入会抛异常,而 int.tryParse 会返回 null。
dart
final min = int.tryParse(_minController.text) ?? 1;
final max = int.tryParse(_maxController.text) ?? 100;
这让页面在空输入或异常输入时仍能继续工作。
15.2 为什么公式里要加 1
nextInt(n) 不包含 n 本身。如果要生成 [min, max] 闭区间,就必须使用 max - min + 1。
dart
final finalResult = min + random.nextInt(max - min + 1);
如果少了 + 1,最大值永远不会出现。
15.3 为什么历史记录插入头部
最新结果通常最重要,因此使用 insert(0, finalResult)。
dart
_history.insert(0, finalResult);
这样历史区域从左到右优先展示最近结果。
15.4 如何避免滚动期间重复点击
当前代码允许滚动期间再次点击。可以使用 _isRolling 禁用按钮。
dart
onPressed: _isRolling ? null : _generateRandom
同时可以让按钮文案跟随状态变化:
dart
label: Text(_isRolling ? 'Rolling...' : 'Generate Random Number')
15.5 如何释放输入控制器
当前代码没有显式释放两个 TextEditingController。更完整的生命周期写法如下:
dart
@override
void dispose() {
_minController.dispose();
_maxController.dispose();
super.dispose();
}
输入控制器属于资源型对象,在正式项目中应在页面销毁时释放。
15.6 如何抽取随机范围函数
可以把随机数生成逻辑抽成纯函数,便于测试。
dart
int generateRandomInRange(int min, int max, math.Random random) {
return min + random.nextInt(max - min + 1);
}
测试时传入固定种子的 Random,可以更容易验证边界行为。
十六、工程扩展方向
16.1 支持清空历史
可以增加清空历史方法。
dart
void _clearHistory() {
setState(() {
_history.clear();
});
}
清空历史适合与历史区域放在一起,让用户能快速恢复初始状态。
16.2 支持复制结果
如果项目引入剪贴板能力,可以把当前结果复制出去。
dart
final current = _result;
if (current != null) {
// Clipboard.setData(ClipboardData(text: current.toString()));
}
复制能力适合抽签、随机编号和测试数据生成场景。
16.3 支持更多随机模式
基于当前结构可以扩展更多模式:
- 随机整数。
- 随机布尔值。
- 随机百分比。
- 随机列表项。
- 随机颜色。
这些模式可以复用输入、结果卡片和历史记录,只需要替换生成逻辑。
16.4 支持状态持久化
历史记录现在只保存在内存中,应用重启后会丢失。后续可以通过本地存储保存最近结果,让用户重启应用后仍能看到历史。
dart
class RandomHistoryStore {
Future<void> save(List<int> history) async {
// 持久化历史记录
}
Future<List<int>> load() async {
// 读取历史记录
return [];
}
}
正式实现时可以根据 OpenHarmony 适配情况选择合适的本地存储方案。
十七、相关链接与延伸阅读
17.1 Flutter 官方资料
| 资料 | 链接 |
|---|---|
| Flutter 官方文档 | https://docs.flutter.dev/ |
| Flutter API 文档 | https://api.flutter.dev/ |
| TextField | https://api.flutter.dev/flutter/material/TextField-class.html |
| SnackBar | https://api.flutter.dev/flutter/material/SnackBar-class.html |
| ScaffoldMessenger | https://api.flutter.dev/flutter/material/ScaffoldMessenger-class.html |
| SingleChildScrollView | https://api.flutter.dev/flutter/widgets/SingleChildScrollView-class.html |
| Wrap | https://api.flutter.dev/flutter/widgets/Wrap-class.html |
| Chip | https://api.flutter.dev/flutter/material/Chip-class.html |
17.2 Dart 与 OpenHarmony 资料
| 资料 | 链接 |
|---|---|
| Dart 官方文档 | https://dart.dev/ |
| Dart API 文档 | https://api.dart.dev/ |
| Random API | https://api.dart.dev/stable/dart-math/Random-class.html |
| pub.dev | https://pub.dev/ |
| OpenHarmony docs | https://github.com/openharmony/docs |
| 开源鸿蒙跨平台社区 | https://openharmonycrossplatform.csdn.net |
总结
random_number 是一个结构清晰的 Flutter 随机数生成器。它通过 TextEditingController 管理最小值和最大值输入,通过 int.tryParse 做安全解析,通过 SnackBar 处理错误范围,通过 math.Random().nextInt(max - min + 1) 生成闭区间随机数,并用 Future.delayed 实现 1 秒滚动数字效果。最终结果会写入 _result,同时插入 _history 头部,历史数量超过 10 条时删除最旧记录。
从 OpenHarmony 适配角度看,这个项目适合验证 Flutter 表单输入、软键盘、SnackBar、异步 UI 刷新、渐变卡片、按钮点击、Wrap 自动换行和 Chip 渲染。由于功能集中在 Flutter 基础组件和 Dart 标准库上,适配问题可以按输入、校验、随机、展示、历史五条链路逐层排查。
掌握这个项目后,可以很自然地扩展到抽签器、随机密码生成器、随机颜色工具、随机列表选择器等应用场景。核心思路保持一致:输入范围要明确,生成公式要覆盖边界,异步刷新要保护生命周期,历史记录要控制容量。
如果这篇文章对你有帮助,欢迎点赞、收藏、关注,你的支持是我持续创作的动力!
相关资源: