在Flutter中创建带分支的关卡进度树实现方案问询
实现分支式关卡进度系统的方案
一、优先选择:自定义Widget实现(轻量且完全可控)
不需要依赖第三方包,直接用Flutter原生的CustomPaint配合状态管理就能实现你要的分支进度树,这也是最灵活的方案,完全适配你的自定义需求:
核心思路
- 用
Stack叠加节点Widget和连线绘制层 - 用
CustomPainter绘制关卡间的连线,通过状态变量控制连线颜色 - 用自定义Widget做关卡节点,根据完成状态切换样式
- 通过
StatefulWidget或状态管理库(Provider/Riverpod)同步关卡完成状态
- 用
基础示例代码
class LevelProgressTree extends StatefulWidget { final Map<int, bool> completedLevels; const LevelProgressTree({super.key, required this.completedLevels}); @override State<LevelProgressTree> createState() => _LevelProgressTreeState(); } class _LevelProgressTreeState extends State<LevelProgressTree> { @override Widget build(BuildContext context) { return Stack( alignment: Alignment.center, children: [ // 绘制关卡连线 CustomPaint( size: const Size(300, 200), painter: _ProgressLinePainter( isLevel1Completed: widget.completedLevels[1] ?? false, isLevel2Completed: widget.completedLevels[2] ?? false, ), ), // 布局关卡节点 Column( mainAxisSize: MainAxisSize.min, children: [ _LevelNode(number: 1, completed: widget.completedLevels[1] ?? false), const SizedBox(height: 60), _LevelNode(number: 2, completed: widget.completedLevels[2] ?? false), const SizedBox(height: 60), Row( mainAxisSize: MainAxisSize.min, children: [ _LevelNode(number: 3, completed: widget.completedLevels[3] ?? false), const SizedBox(width: 80), _LevelNode(number: 4, completed: widget.completedLevels[4] ?? false), ], ), ], ), ], ); } } // 自定义连线绘制器 class _ProgressLinePainter extends CustomPainter { final bool isLevel1Completed; final bool isLevel2Completed; _ProgressLinePainter({required this.isLevel1Completed, required this.isLevel2Completed}); @override void paint(Canvas canvas, Size size) { // 关卡1→关卡2的连线 final line1Paint = Paint() ..strokeWidth = 3 ..color = isLevel1Completed ? Colors.green : Colors.grey.shade400; canvas.drawLine( Offset(size.width / 2, 20), Offset(size.width / 2, 80), line1Paint, ); // 关卡2→关卡3、关卡2→关卡4的分支连线 final branchPaint = Paint() ..strokeWidth = 3 ..color = isLevel2Completed ? Colors.green : Colors.grey.shade400; canvas.drawLine( Offset(size.width / 2, 140), Offset(size.width / 2 - 40, 200), branchPaint, ); canvas.drawLine( Offset(size.width / 2, 140), Offset(size.width / 2 + 40, 200), branchPaint, ); } @override bool shouldRepaint(covariant _ProgressLinePainter oldDelegate) { return oldDelegate.isLevel1Completed != isLevel1Completed || oldDelegate.isLevel2Completed != isLevel2Completed; } } // 自定义关卡节点 class _LevelNode extends StatelessWidget { final int number; final bool completed; const _LevelNode({required this.number, required this.completed}); @override Widget build(BuildContext context) { return Container( width: 50, height: 50, decoration: BoxDecoration( color: completed ? Colors.green : Colors.white, border: Border.all(color: Colors.grey.shade600), borderRadius: BorderRadius.circular(25), ), child: Center( child: Text( number.toString(), style: TextStyle( color: completed ? Colors.white : Colors.black, fontWeight: FontWeight.bold, fontSize: 18, ), ), ), ); } }
二、Flame的适用场景
如果你的应用本身是基于Flame引擎开发的游戏,那用Flame的组件系统实现会更契合:
- 用
PositionComponent封装关卡节点 - 用
LineComponent绘制关卡间的连线,通过修改LineComponent的paint.color属性更新连线状态 - 借助Flame的状态管理机制同步关卡进度
但如果只是单纯的UI界面,没必要引入Flame,自定义Widget方案更轻量。
三、可选第三方包
可以尝试graphview包,它支持绘制树形/图结构,能快速搭建分支式进度树:
- 配置节点的依赖关系(比如关卡2解锁后显示关卡3、4)
- 自定义节点和边的样式,通过监听关卡状态修改边的颜色
内容的提问来源于stack exchange,提问作者Rens van Melis
相关产品推荐
相关产品推荐

