如何在Flutter中自定义进度指示器?求Figma设计还原方案
自定义Flutter进度指示器实现方案
针对你需要还原的Figma设计进度指示器,以下提供两种自定义实现方案(无需依赖第三方包),可根据设计样式选择适配:
方案一:横向分段进度指示器
适合线性步骤类的进度展示,包含节点状态、进度条和步骤标题,可精准匹配设计细节:
import 'package:flutter/material.dart'; class SegmentProgressIndicator extends StatelessWidget { final int totalSteps; final int currentStep; final Color completedColor; final Color activeColor; final Color inactiveColor; const SegmentProgressIndicator({ super.key, required this.totalSteps, required this.currentStep, this.completedColor = Colors.green, this.activeColor = Colors.blue, this.inactiveColor = Colors.grey.shade300, }) : assert(currentStep >= 1 && currentStep <= totalSteps, "当前步骤必须在1到总步骤之间"); @override Widget build(BuildContext context) { return Row( children: List.generate(totalSteps, (index) { final step = index + 1; final isCompleted = step < currentStep; final isActive = step == currentStep; final isInactive = step > currentStep; return Expanded( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // 进度节点 Container( width: 24, height: 24, decoration: BoxDecoration( shape: BoxShape.circle, color: isCompleted ? completedColor : isActive ? activeColor : inactiveColor, border: isInactive ? Border.all(color: inactiveColor) : null, ), child: isCompleted ? const Icon(Icons.check, color: Colors.white, size: 16) : Text( step.toString(), style: TextStyle(color: isActive ? Colors.white : inactiveColor), ), ), const SizedBox(height: 8), // 步骤标题(可根据设计删除或修改) Text( "步骤$step", style: TextStyle( color: isCompleted || isActive ? Colors.black87 : inactiveColor, fontSize: 12, ), ), ], ), ); }).expand((widget) { final index = (widget.key as ValueKey<int>).value; // 添加节点间的进度条 if (index < totalSteps) { return [ widget, Expanded( child: Container( height: 2, color: (index + 1) < currentStep ? completedColor : (index + 1) == currentStep ? activeColor : inactiveColor, ), ), ]; } return [widget]; }).toList(), ); } } // 使用示例 class ProgressDemo extends StatelessWidget { const ProgressDemo({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("分段进度指示器")), body: const Padding( padding: EdgeInsets.all(20.0), child: SegmentProgressIndicator( totalSteps: 4, currentStep: 2, ), ), ); } }
方案二:环形分段进度指示器
适合环形类的进度展示,支持分段填充、中心文字显示:
import 'package:flutter/material.dart'; import 'dart:math' as math; class CircularSegmentProgress extends CustomPainter { final int totalSegments; final int currentSegment; final Color completedColor; final Color activeColor; final Color inactiveColor; final double strokeWidth; CircularSegmentProgress({ required this.totalSegments, required this.currentSegment, this.completedColor = Colors.green, this.activeColor = Colors.blue, this.inactiveColor = Colors.grey.shade300, this.strokeWidth = 8.0, }); @override void paint(Canvas canvas, Size size) { final center = Offset(size.width / 2, size.height / 2); final radius = (size.width - strokeWidth) / 2; final segmentAngle = 2 * math.pi / totalSegments; // 绘制未完成分段 for (int i = currentSegment; i < totalSegments; i++) { final startAngle = i * segmentAngle - math.pi / 2; canvas.drawArc( Rect.fromCircle(center: center, radius: radius), startAngle, segmentAngle, false, Paint() ..color = inactiveColor ..strokeWidth = strokeWidth ..style = PaintingStyle.stroke ..strokeCap = StrokeCap.round, ); } // 绘制已完成分段 for (int i = 0; i < currentSegment - 1; i++) { final startAngle = i * segmentAngle - math.pi / 2; canvas.drawArc( Rect.fromCircle(center: center, radius: radius), startAngle, segmentAngle, false, Paint() ..color = completedColor ..strokeWidth = strokeWidth ..style = PaintingStyle.stroke ..strokeCap = StrokeCap.round, ); } // 绘制当前活跃分段 if (currentSegment <= totalSegments) { final startAngle = (currentSegment - 1) * segmentAngle - math.pi / 2; canvas.drawArc( Rect.fromCircle(center: center, radius: radius), startAngle, segmentAngle, false, Paint() ..color = activeColor ..strokeWidth = strokeWidth ..style = PaintingStyle.stroke ..strokeCap = StrokeCap.round, ); } // 绘制中心进度文字 final textPainter = TextPainter( text: TextSpan( text: "$currentSegment/$totalSegments", style: const TextStyle(color: Colors.black87, fontSize: 16, fontWeight: FontWeight.bold), ), textDirection: TextDirection.ltr, ); textPainter.layout(); textPainter.paint( canvas, Offset(center.dx - textPainter.width / 2, center.dy - textPainter.height / 2), ); } @override bool shouldRepaint(CircularSegmentProgress oldDelegate) { return oldDelegate.currentSegment != currentSegment || oldDelegate.totalSegments != totalSegments; } } // 使用示例 class CircularProgressDemo extends StatelessWidget { const CircularProgressDemo({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("环形分段进度指示器")), body: const Center( child: SizedBox( width: 120, height: 120, child: CustomPaint( painter: CircularSegmentProgress( totalSegments: 4, currentSegment: 2, ), ), ), ), ); } }
自定义适配说明
- 可修改
completedColor、activeColor、节点尺寸、图标、文字样式等参数,完全匹配Figma设计 - 若设计有特殊交互(如点击节点切换进度),可在组件内添加
GestureDetector实现
内容的提问来源于stack exchange,提问作者Ukeme Elijah
相关产品推荐
相关产品推荐

