1. 项目背景与目标
最近在OpenHarmony平台上用Flutter开发了一款数独游戏App,今天重点分享其中"胜利弹窗"功能的实现过程。这个看似简单的UI交互,实际上涉及跨平台框架适配、状态管理、动画效果等多个技术点的融合。
对于移动应用开发来说,游戏结束时的反馈机制直接影响用户体验。一个好的胜利弹窗应该:
- 及时准确地判断游戏胜利条件
- 提供清晰的结果展示
- 包含合理的交互选项
- 具备吸引人的动效表现
2. 技术选型与架构设计
2.1 Flutter on OpenHarmony的适配要点
在OpenHarmony上运行Flutter应用需要注意:
- 使用ohos_flutter插件桥接鸿蒙原生能力
- 适配鸿蒙特有的权限管理系统
- 处理鸿蒙设备的分辨率适配问题
dart复制// 鸿蒙平台初始化示例
void main() {
WidgetsFlutterBinding.ensureInitialized();
if (Platform.isOpenHarmony) {
initOpenHarmonyServices();
}
runApp(MySudokuApp());
}
2.2 状态管理方案选择
经过对比几种方案后选择了Riverpod:
- 比Provider更灵活的状态管理
- 更好的测试支持
- 与Flutter Hooks配合良好
胜利状态的判断逻辑:
dart复制final gameStateProvider = StateNotifierProvider<GameStateNotifier, GameState>((ref) {
return GameStateNotifier();
});
class GameStateNotifier extends StateNotifier<GameState> {
// 校验数独完成状态的逻辑
bool checkVictory() {
// 行、列、宫格的校验算法
}
}
3. 胜利弹窗实现细节
3.1 弹窗布局构建
采用自定义Dialog组件而非系统弹窗,实现更灵活的UI:
dart复制class VictoryDialog extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Material(
type: MaterialType.transparency,
child: Container(
width: MediaQuery.of(context).size.width * 0.8,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
gradient: LinearGradient(...),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// 胜利图标
// 用时统计
// 按钮组
],
),
),
),
);
}
}
3.2 动画效果实现
使用Flutter动画系统实现入场动效:
dart复制AnimationController _controller;
Animation<double> _scaleAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 300),
vsync: this,
);
_scaleAnimation = Tween<double>(begin: 0.7, end: 1.0).animate(
CurvedAnimation(parent: _controller, curve: Curves.easeOutBack),
);
_controller.forward();
}
4. 性能优化与问题排查
4.1 常见性能问题
-
过度绘制问题:
- 使用DevTools的Performance overlay检测
- 简化弹窗层级结构
- 对静态元素使用RepaintBoundary
-
动画卡顿:
- 避免在动画构建中执行耗时操作
- 使用硬件加速(addRepaintBoundary)
- 控制动画复杂度
4.2 鸿蒙平台特有适配问题
问题现象:弹窗显示位置偏移
解决方案:
dart复制// 鸿蒙设备需要特殊处理安全区域
SafeArea(
child: VictoryDialog(),
)
问题现象:动画性能下降
解决方案:
- 开启鸿蒙的GPU渲染模式
- 降低阴影等特效的复杂度
5. 扩展功能实现
5.1 数据统计与分享
胜利弹窗集成游戏数据:
- 完成时间
- 难度等级
- 历史最佳记录对比
dart复制final statsProvider = FutureProvider<GameStats>((ref) async {
final time = ref.watch(gameTimerProvider);
final difficulty = ref.watch(difficultyProvider);
return await saveGameResult(time, difficulty);
});
5.2 国际化支持
使用flutter_localizations实现多语言:
yaml复制# 弹窗文案国际化配置
victory_title:
en: "Congratulations!"
zh: "恭喜获胜!"
victory_message:
en: "You solved the puzzle in %{time}"
zh: "您在%{time}内完成了谜题"
6. 测试策略
6.1 单元测试要点
dart复制test('should trigger victory when board is complete', () {
final notifier = GameStateNotifier();
// 填充完成的数独盘面
notifier.updateBoard(completedBoard);
expect(notifier.state.status, GameStatus.victory);
});
6.2 集成测试流程
使用flutter_driver测试完整流程:
dart复制test('victory dialog appears after completion', () async {
// 模拟填写数字
await driver.tap(find.text('5'));
// ...
// 验证弹窗出现
expect(await driver.getText(find.text('Congratulations!')), isNotNull);
});
7. 项目收获与优化方向
在实际开发中发现几个值得注意的点:
-
状态管理粒度:最初将整个游戏状态放在单一Provider中,后来拆分为多个细粒度Provider提升性能
-
动画性能平衡:在低端鸿蒙设备上需要简化动画效果,通过Platform.isAndroid判断设备等级
-
弹窗交互设计:添加了震动反馈等鸿蒙特性增强体验:
dart复制if (Platform.isOpenHarmony) {
await HapticFeedback.vibrate(HapticType.impact);
}
后续优化方向:
- 增加成就系统
- 实现云端存档
- 开发AR模式下的数独体验