🚀运行效果展示


Flutter框架跨平台鸿蒙开发------记忆力练习APP开发流程
一、前言
1.1 Flutter跨平台开发的优势
Flutter作为Google推出的开源UI框架,凭借其**"一次编写,到处运行"的特性,以及 原生性能和丰富的组件库**,已成为跨平台开发的重要选择。Flutter采用Dart语言开发,编译成原生代码,性能接近原生应用,同时拥有热重载功能,大幅提高开发效率。
1.2 鸿蒙系统的发展前景
华为鸿蒙系统(HarmonyOS)是一款面向全场景的分布式操作系统,具有分布式架构 、统一生态 和安全可靠等优势。随着鸿蒙生态的不断完善,越来越多的开发者开始关注鸿蒙应用开发,Flutter与鸿蒙的结合为跨平台开发开辟了新的可能性。
1.3 记忆力练习APP开发意义
本项目旨在探索Flutter框架在鸿蒙系统上的应用,开发一款功能完整的记忆力练习APP。通过该项目,我们将深入了解Flutter跨平台开发的实践,以及如何在鸿蒙系统上进行应用适配和优化。
二、游戏介绍
2.1 应用概述
记忆力练习APP是一款通过翻牌匹配游戏来锻炼记忆力的移动应用。玩家需要在限定时间内,通过最少的步数找到所有匹配的卡片对。游戏提供多种难度级别,适合不同年龄段的用户。
2.2 核心功能
| 功能模块 | 功能描述 | 技术要点 |
|---|---|---|
| 🎯 难度选择 | 提供简单、中等、困难三种难度 | 动态卡片数量生成 |
| 🃏 卡片翻转 | 点击卡片进行翻转,显示卡片内容 | 动画效果实现 |
| 🔍 匹配检测 | 自动检测两张卡片是否匹配 | 游戏逻辑处理 |
| ⏱️ 用时计时 | 实时记录游戏用时 | 计时器实现 |
| 📊 步数统计 | 统计玩家的翻牌步数 | 状态管理 |
| 🎉 游戏结束 | 显示游戏成绩,支持重新开始 | 对话框实现 |
2.3 技术栈
| 技术 | 版本/说明 |
|---|---|
| 开发框架 | Flutter 3.0+ |
| 编程语言 | Dart |
| 运行环境 | HarmonyOS 2.0+ |
| 架构模式 | MVVM |
| 状态管理 | StatefulWidget + Provider |
| UI组件 | Material Design |
三、开发流程与架构设计
3.1 开发流程图
项目初始化
环境配置
架构设计
数据模型设计
服务层实现
UI界面开发
功能测试
跨平台适配
集成到主应用
发布与部署
3.2 项目架构设计
采用模块化架构,将项目划分为多个功能模块,每个模块负责特定的功能,便于维护和扩展。
lib/
├── memory_game/ # 记忆力游戏模块
│ ├── models/ # 数据模型
│ │ └── card_model.dart # 卡片模型
│ ├── services/ # 服务层
│ │ └── game_service.dart # 游戏服务
│ └── screens/ # 界面层
│ └── memory_game_screen.dart # 游戏主屏幕
└── screens/ # 主应用
└── home_screen.dart # 主界面
四、核心功能实现与代码展示
4.1 数据模型设计
MemoryCard类用于存储卡片的核心信息,包括ID、内容、翻转状态和匹配状态。
dart
/// 记忆卡片模型
class MemoryCard {
/// 卡片ID
final int id;
/// 卡片内容(用于匹配)
final String content;
/// 卡片是否已翻转
bool isFlipped;
/// 卡片是否已匹配
bool isMatched;
/// 构造函数
MemoryCard({
required this.id,
required this.content,
this.isFlipped = false,
this.isMatched = false,
});
/// 翻转卡片
void flip() {
isFlipped = !isFlipped;
}
/// 将卡片标记为已匹配
void match() {
isMatched = true;
}
}
4.2 游戏服务实现
GameService类提供了生成卡片、检查匹配、重置卡片等核心游戏逻辑。
dart
import '../models/card_model.dart';
/// 记忆游戏服务类
class MemoryGameService {
/// 卡片内容列表(成对出现)
static const List<String> _cardContents = [
'🎈', '🎈', '🎨', '🎨', '🎪', '🎪', '🎭', '🎭',
'🎯', '🎯', '🎲', '🎲', '🎸', '🎸', '🎹', '🎹',
'🎺', '🎺', '🎻', '🎻', '🎼', '🎼', '🎾', '🎾',
];
/// 生成指定数量的卡片(必须是偶数)
List<MemoryCard> generateCards(int cardCount) {
if (cardCount % 2 != 0) {
throw ArgumentError('卡片数量必须是偶数');
}
if (cardCount > _cardContents.length) {
throw ArgumentError('卡片数量超出最大限制');
}
// 随机选择卡片内容
final selectedContents = _cardContents.sublist(0, cardCount);
selectedContents.shuffle();
// 创建卡片列表
final cards = <MemoryCard>[];
for (var i = 0; i < selectedContents.length; i++) {
cards.add(MemoryCard(
id: i,
content: selectedContents[i],
));
}
return cards;
}
/// 检查两张卡片是否匹配
bool checkMatch(MemoryCard card1, MemoryCard card2) {
return card1.content == card2.content;
}
/// 重置卡片状态
void resetCards(List<MemoryCard> cards) {
for (var card in cards) {
card.isFlipped = false;
card.isMatched = false;
}
}
/// 洗牌
void shuffleCards(List<MemoryCard> cards) {
final contents = cards.map((card) => card.content).toList();
contents.shuffle();
for (var i = 0; i < cards.length; i++) {
cards[i] = MemoryCard(
id: cards[i].id,
content: contents[i],
isFlipped: false,
isMatched: false,
);
}
}
}
4.3 游戏主屏幕实现
MemoryGameScreen是游戏的核心界面,包含难度选择、卡片网格、游戏状态显示和重新开始功能。
dart
import 'dart:async';
import 'package:flutter/material.dart';
import '../models/card_model.dart';
import '../services/game_service.dart';
/// 记忆游戏主屏幕
class MemoryGameScreen extends StatefulWidget {
/// 构造函数
const MemoryGameScreen({super.key});
@override
State<MemoryGameScreen> createState() => _MemoryGameScreenState();
}
class _MemoryGameScreenState extends State<MemoryGameScreen> {
/// 游戏服务实例
final MemoryGameService _gameService = MemoryGameService();
/// 游戏难度级别
int _difficulty = 2; // 1: 简单(8张), 2: 中等(16张), 3: 困难(24张)
/// 卡片列表
List<MemoryCard> _cards = [];
/// 当前翻转的卡片
MemoryCard? _firstCard;
MemoryCard? _secondCard;
/// 游戏是否正在进行(防止连续点击)
bool _isPlaying = false;
/// 游戏是否已结束
bool _isGameOver = false;
/// 步数
int _steps = 0;
/// 开始时间
DateTime? _startTime;
/// 用时(秒)
int _elapsedSeconds = 0;
/// 计时器
late final Timer _timer;
@override
void initState() {
super.initState();
// 初始化计时器
_timer = Timer.periodic(const Duration(seconds: 1), (_) {
if (_startTime != null && !_isGameOver) {
setState(() {
_elapsedSeconds = DateTime.now().difference(_startTime!).inSeconds;
});
}
});
// 初始化游戏
_initializeGame();
}
@override
void dispose() {
_timer.cancel();
super.dispose();
}
/// 初始化游戏
void _initializeGame() {
// 根据难度设置卡片数量
final cardCount = _getCardCountByDifficulty(_difficulty);
// 生成卡片
final cards = _gameService.generateCards(cardCount);
setState(() {
_cards = cards;
_firstCard = null;
_secondCard = null;
_isPlaying = false;
_isGameOver = false;
_steps = 0;
_startTime = DateTime.now();
_elapsedSeconds = 0;
});
}
/// 根据难度获取卡片数量
int _getCardCountByDifficulty(int difficulty) {
switch (difficulty) {
case 1: return 8;
case 2: return 16;
case 3: return 24;
default: return 16;
}
}
/// 处理卡片点击
void _onCardTap(MemoryCard card) {
// 如果游戏正在进行或卡片已翻转/匹配,不处理点击
if (_isPlaying || card.isFlipped || card.isMatched) {
return;
}
setState(() {
// 翻转当前卡片
card.flip();
// 记录翻转的卡片
if (_firstCard == null) {
_firstCard = card;
} else {
_secondCard = card;
_steps++;
_isPlaying = true;
}
});
// 如果两张卡片都已翻转,检查是否匹配
if (_firstCard != null && _secondCard != null) {
_checkMatch();
}
}
/// 检查卡片匹配
void _checkMatch() {
Future.delayed(const Duration(seconds: 1), () {
setState(() {
if (_gameService.checkMatch(_firstCard!, _secondCard!)) {
// 卡片匹配
_firstCard!.match();
_secondCard!.match();
} else {
// 卡片不匹配,翻转回来
_firstCard!.flip();
_secondCard!.flip();
}
// 重置当前翻转的卡片
_firstCard = null;
_secondCard = null;
_isPlaying = false;
// 检查游戏是否结束
_checkGameOver();
});
});
}
/// 检查游戏是否结束
void _checkGameOver() {
final allMatched = _cards.every((card) => card.isMatched);
if (allMatched) {
setState(() {
_isGameOver = true;
});
}
}
/// 格式化时间(秒 -> mm:ss)
String _formatTime(int seconds) {
final minutes = seconds ~/ 60;
final remainingSeconds = seconds % 60;
return '${minutes.toString().padLeft(2, '0')}:${remainingSeconds.toString().padLeft(2, '0')}';
}
/// 构建难度按钮
Widget _buildDifficultyButton(int difficulty, String label) {
return Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 4.0),
child: ElevatedButton(
onPressed: () {
setState(() {
_difficulty = difficulty;
});
_initializeGame();
},
style: ElevatedButton.styleFrom(
backgroundColor: _difficulty == difficulty ? Colors.blue : Colors.grey[300],
foregroundColor: _difficulty == difficulty ? Colors.white : Colors.black,
minimumSize: const Size(0, 40),
),
child: Text(label, textAlign: TextAlign.center),
),
),
);
}
/// 构建游戏信息栏
Widget _buildGameInfo() {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 难度选择
const Text(
'选择难度:',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Row(
children: [
_buildDifficultyButton(1, '简单 (8张)'),
_buildDifficultyButton(2, '中等 (16张)'),
_buildDifficultyButton(3, '困难 (24张)'),
],
),
const SizedBox(height: 20),
// 游戏状态
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
children: [
const Text('步数:', style: TextStyle(fontSize: 14)),
Text('$_steps', style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
],
),
Column(
children: [
const Text('用时:', style: TextStyle(fontSize: 14)),
Text(_formatTime(_elapsedSeconds), style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
],
),
ElevatedButton(
onPressed: _initializeGame,
child: const Text('重新开始'),
),
],
),
],
),
);
}
/// 构建卡片网格
Widget _buildCardGrid() {
// 根据卡片数量确定网格列数
final columnCount = _cards.length == 8 ? 4 : _cards.length == 16 ? 4 : 6;
return Expanded(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: columnCount,
mainAxisSpacing: 12.0,
crossAxisSpacing: 12.0,
childAspectRatio: 1.0,
),
itemCount: _cards.length,
itemBuilder: (context, index) {
final card = _cards[index];
return _buildCard(card);
},
),
),
);
}
/// 构建单个卡片
Widget _buildCard(MemoryCard card) {
return GestureDetector(
onTap: () => _onCardTap(card),
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
decoration: BoxDecoration(
color: card.isFlipped || card.isMatched ? Colors.white : Colors.blue,
borderRadius: BorderRadius.circular(12.0),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.2),
blurRadius: 4.0,
offset: const Offset(0, 2),
),
],
),
child: Center(
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
transitionBuilder: (child, animation) {
return ScaleTransition(
scale: animation,
child: child,
);
},
child: card.isFlipped || card.isMatched
? Text(
card.content,
key: ValueKey(card.content),
style: const TextStyle(fontSize: 40.0),
)
: const Icon(
Icons.question_mark,
key: ValueKey('question'),
size: 40.0,
color: Colors.white,
),
),
),
),
);
}
/// 构建游戏结束对话框
Widget _buildGameOverDialog() {
return AlertDialog(
title: const Text('🎉 游戏结束!'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 16.0),
Text('总步数: $_steps', style: const TextStyle(fontSize: 18.0)),
Text('用时: ${_formatTime(_elapsedSeconds)}', style: const TextStyle(fontSize: 18.0)),
const SizedBox(height: 24.0),
const Text('恭喜你完成了游戏!', style: const TextStyle(fontSize: 16.0)),
],
),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
_initializeGame();
},
child: const Text('再玩一次'),
),
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('返回主页'),
),
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('记忆力游戏'),
backgroundColor: Colors.blue,
centerTitle: true,
elevation: 0,
),
body: SafeArea(
child: Column(
children: [
// 游戏信息
_buildGameInfo(),
// 卡片网格
_buildCardGrid(),
],
),
),
// 游戏结束对话框
floatingActionButton: _isGameOver
? FloatingActionButton.extended(
onPressed: () {
showDialog(
context: context,
builder: (_) => _buildGameOverDialog(),
);
},
label: const Text('查看成绩'),
icon: const Icon(Icons.emoji_events),
)
: null,
);
}
}
4.4 与主应用集成
将记忆力游戏集成到主应用的功能卡片列表中:
dart
// 导入记忆力游戏屏幕
import '../memory_game/screens/memory_game_screen.dart';
// 在功能卡片列表中添加记忆力游戏卡片
_buildFunctionCard(
context: context,
title: '记忆力游戏',
description: '锻炼记忆力,挑战不同难度',
icon: Icons.gamepad,
color: Colors.purple,
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const MemoryGameScreen(),
),
);
},
),
五、跨平台适配与优化
5.1 鸿蒙系统适配
-
分辨率适配 :使用
GridView.builder和Expanded组件,确保界面在不同尺寸的鸿蒙设备上都能正常显示。 -
性能优化:
- 卡片翻转动画使用
AnimatedContainer和AnimatedSwitcher,确保流畅过渡 - 游戏逻辑中避免不必要的重建和重绘
- 使用
Timer.periodic实现高效计时
- 卡片翻转动画使用
-
用户体验优化:
- 清晰的游戏状态反馈
- 直观的难度选择
- 流畅的卡片翻转动画
- 游戏结束后的成绩展示
5.2 Flutter跨平台优势体现
| 优势 | 具体表现 |
|---|---|
| 单一代码库 | 一套代码同时支持Android、iOS、HarmonyOS等平台 |
| 原生性能 | 编译成原生代码,性能接近原生应用 |
| 热重载 | 开发过程中实时预览修改效果,提高开发效率 |
| 丰富的组件库 | 内置Material Design组件,快速构建美观界面 |
| 活跃的社区 | 丰富的第三方插件和资源,加速开发进程 |
六、总结与展望
6.1 项目总结
本项目成功实现了基于Flutter框架的跨平台鸿蒙记忆力练习APP,主要完成了以下工作:
-
架构设计:采用模块化架构,清晰划分数据模型、服务层和界面层,便于维护和扩展。
-
核心功能:实现了卡片翻转、匹配检测、难度选择、步数统计、用时计时等核心功能。
-
UI设计:创建了精美的游戏界面,包含流畅的动画效果和直观的用户交互。
-
跨平台适配:针对鸿蒙系统进行了适配和优化,确保应用在鸿蒙设备上有良好的运行效果。
-
与主应用集成:成功将记忆力游戏功能集成到主应用中,作为一个独立的功能模块。
七、参考资源
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net