这个逆向思维训练App的核心模块之一就是数列推理功能。作为一名长期从事移动应用开发的工程师,我发现数列推理训练对于提升逻辑思维能力有着显著效果。在这个项目中,我们使用Flutter框架开发,同时兼容OpenHarmony平台,实现了一个轻量级但功能完整的数列推理训练模块。
整个模块的设计遵循了"简单但严谨"的原则:
提示:虽然项目使用了Flutter for OpenHarmony,但核心代码完全遵循标准Flutter开发规范,可以无缝运行在Android/iOS等其他平台。
项目采用典型的Flutter分层架构:
code复制lib/
├── main.dart # 应用入口
├── app.dart # 根Widget和主页面结构
└── feature_pages/ # 功能模块
└── sequence_reasoning.dart # 数列推理核心实现
这种结构的特点是:
导航系统设计采用了"模块化入口"的思路:
dart复制// 在app.dart中定义主框架
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: DefaultTabController(
length: 4,
child: Scaffold(
body: TabBarView(
children: [
HomePage(),
PatternRecognitionPage(), // 模式识别模块
MemoryTrainingPage(),
SettingsPage()
],
),
),
),
);
}
}
在PatternRecognitionPage中,我们使用_buildFeatureCard方法统一创建各个训练项目的入口卡片:
dart复制Widget _buildFeatureCard(BuildContext context, String title, IconData icon, Widget page) {
return Card(
child: InkWell(
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => page)),
child: Padding(
padding: EdgeInsets.all(16.w),
child: Column(
children: [
Icon(icon, size: 32.w),
SizedBox(height: 8.h),
Text(title, style: TextStyle(fontSize: 14.sp)),
],
),
),
),
);
}
这种设计的好处是:
数列推理模块的核心数据采用三个平行列表存储:
dart复制final List<List<int>> sequences = [
[1, 4, 9, 16, 25], // 平方数
[2, 3, 5, 7, 11], // 质数
[1, 1, 2, 3, 5], // 斐波那契
[2, 6, 12, 20, 30],// n*(n+1)
[3, 9, 27, 81, 243],// 3的幂次
];
final List<String> answers = ['36', '13', '8', '42', '729'];
final List<String> patterns = [
'平方数序列:n²(n从1开始)',
'质数序列:只能被1和自身整除的数',
'斐波那契数列:前两项之和等于后一项',
'n*(n+1)序列:相邻两个自然数的乘积',
'3的幂次序列:3ⁿ(n从1开始)'
];
这种设计在小规模静态题库中优势明显:
注意事项:必须确保三个列表长度一致,可以在初始化时添加断言检查:
dart复制assert(sequences.length == answers.length && answers.length == patterns.length);
SequenceReasoningPage使用StatefulWidget管理三种核心状态:
dart复制class _SequenceReasoningPageState extends State<SequenceReasoningPage> {
int currentSequence = 0; // 当前题目索引
String? userAnswer; // 用户答案
bool showResult = false; // 是否显示结果
// 其他代码...
}
状态设计遵循最小化原则:
这种轻量级的状态管理完全满足当前需求,无需引入复杂的状态管理库。
页面采用典型的Column布局结构:
dart复制@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('数列推理')),
body: Padding(
padding: EdgeInsets.all(16.w),
child: Column(
children: [
// 1. 标题
Text('找出下一个数字', style: TextStyle(fontSize: 20.sp, fontWeight: FontWeight.bold)),
// 2. 数列展示区
_buildSequenceDisplay(),
// 3. 输入区
_buildAnswerInput(),
// 4. 确认按钮
_buildSubmitButton(),
// 5. 结果展示区
if (showResult) _buildResultDisplay(),
// 6. 题目导航
Spacer(),
_buildNavigationButtons(),
],
),
),
);
}
数列展示采用了圆形数字卡片的设计,增强视觉识别度:
dart复制Widget _buildSequenceDisplay() {
return Container(
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
color: Colors.blue[50],
borderRadius: BorderRadius.circular(12.r),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
// 已知数列项
...sequences[currentSequence].map((num) => Container(
width: 40.w,
height: 40.w,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(20.r),
),
child: Center(child: Text(num.toString(),
style: TextStyle(color: Colors.white, fontSize: 16.sp))),
)),
// 未知项问号
Container(
width: 40.w,
height: 40.w,
decoration: BoxDecoration(
color: Colors.grey,
borderRadius: BorderRadius.circular(20.r),
border: Border.all(color: Colors.blue, width: 2),
),
child: Center(child: Text('?',
style: TextStyle(color: Colors.blue, fontSize: 16.sp))),
),
],
),
);
}
设计要点:
输入验证流程设计为三步:
dart复制Widget _buildAnswerInput() {
return TextField(
decoration: const InputDecoration(
labelText: '你的答案',
border: OutlineInputBorder(),
),
keyboardType: TextInputType.number,
onChanged: (value) => userAnswer = value.trim(),
);
}
Widget _buildSubmitButton() {
return ElevatedButton(
onPressed: userAnswer?.isNotEmpty == true
? () => setState(() => showResult = true)
: null,
child: const Text('确认答案'),
);
}
关键细节:
结果展示采用颜色编码+详细解析的方式:
dart复制Widget _buildResultDisplay() {
final isCorrect = userAnswer == answers[currentSequence];
return Container(
padding: EdgeInsets.all(12.w),
decoration: BoxDecoration(
color: isCorrect ? Colors.green[100] : Colors.red[100],
borderRadius: BorderRadius.circular(8.r),
),
child: Column(
children: [
Text('正确答案:${answers[currentSequence]}',
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w500)),
SizedBox(height: 8.h),
Text('规律:${patterns[currentSequence]}',
style: TextStyle(fontSize: 14.sp, color: Colors.grey[700])),
],
),
);
}
设计考虑:
题目导航按钮组实现:
dart复制Widget _buildNavigationButtons() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: currentSequence > 0 ? () => _goToPrevious() : null,
child: const Text('上一题'),
),
ElevatedButton(
onPressed: currentSequence < sequences.length - 1 ? () => _goToNext() : null,
child: const Text('下一题'),
),
],
);
}
void _goToPrevious() {
setState(() {
currentSequence--;
_resetQuestionState();
});
}
void _goToNext() {
setState(() {
currentSequence++;
_resetQuestionState();
});
}
void _resetQuestionState() {
userAnswer = null;
showResult = false;
FocusScope.of(context).unfocus(); // 收起键盘
}
关键实现细节:
在这个模块中,我们遵循了几个重要的状态管理原则:
这些实践保证了代码的可维护性和性能表现。
dart复制const SequenceReasoningPage({super.key}); // 在导航时使用const构造
dart复制Widget _buildSequenceDisplay() { ... } // 提取数列展示逻辑
使用flutter_screenutil实现完美适配:
dart复制// 初始化
void main() {
runApp(ScreenUtilInit(
designSize: const Size(360, 690),
minTextAdapt: true,
splitScreenMode: true,
builder: (_, child) => MyApp(),
));
}
// 使用
Container(
width: 40.w, // 适配宽度
height: 40.w,
margin: EdgeInsets.all(10.h), // 适配高度
child: Text('文本', style: TextStyle(fontSize: 14.sp)), // 适配字体
)
当题目数量增加时,可以考虑改用模型类:
dart复制class SequencePuzzle {
final List<int> sequence;
final String answer;
final String pattern;
final String difficulty;
const SequencePuzzle({
required this.sequence,
required this.answer,
required this.pattern,
this.difficulty = 'easy',
});
}
final List<SequencePuzzle> puzzles = [
SequencePuzzle(
sequence: [1,4,9,16,25],
answer: '36',
pattern: '平方数序列:n²(n从1开始)',
difficulty: 'easy'
),
// 更多题目...
];
针对OpenHarmony平台的特别优化:
问题:用户输入"036"或"36 "会导致验证失败
解决方案:
dart复制bool isAnswerCorrect(String userAnswer, String correctAnswer) {
// 方案1:简单trim
// return userAnswer.trim() == correctAnswer;
// 方案2:转为数字比较
try {
return int.parse(userAnswer.trim()) == int.parse(correctAnswer);
} catch (e) {
return false;
}
}
问题:页面滚动/动画卡顿
解决方案:
问题:状态意外重置或不同步
解决方案:
通过这个数列推理模块的开发,我总结了以下几点经验:
这个模块虽然不大,但涵盖了Flutter开发的多个核心概念:
对于想要学习Flutter的开发者,我建议从这样的小而完整的模块开始实践,逐步掌握Flutter的开发模式和思维方式。