如何在Flutter中实现这种锯齿形进度指示器设计?
实现Flutter锯齿形进度指示器(含自定义完成对勾)
针对你需要的推进式锯齿进度指示器,我们可以通过CustomPainter精准实现,以下是完整的可复用方案:
核心绘制逻辑(CustomPainter)
创建自定义绘制类,处理锯齿路径、进度填充和完成对勾的绘制:
import 'package:flutter/material.dart'; class SawtoothProgressPainter extends CustomPainter { final int totalSteps; final int completedSteps; final Color completedColor; final Color incompleteColor; final Color checkmarkColor; final double toothHeight; final double toothWidth; SawtoothProgressPainter({ required this.totalSteps, required this.completedSteps, this.completedColor = Colors.green, this.incompleteColor = Colors.grey.shade300, this.checkmarkColor = Colors.white, this.toothHeight = 20.0, this.toothWidth = 30.0, }); @override void paint(Canvas canvas, Size size) { final paint = Paint()..style = PaintingStyle.fill; final path = Path(); // 绘制完整锯齿路径框架 path.moveTo(0, size.height / 2); for (int i = 0; i < totalSteps; i++) { final x = i * toothWidth; path.lineTo(x + toothWidth / 2, size.height / 2 - toothHeight / 2); path.lineTo(x + toothWidth, size.height / 2 + toothHeight / 2); } path.lineTo(size.width, size.height); path.lineTo(0, size.height); path.close(); // 绘制未完成部分底色 paint.color = incompleteColor; canvas.drawPath(path, paint); // 绘制已完成部分填充色 final completedWidth = completedSteps * toothWidth; final clipRect = Rect.fromLTWH(0, 0, completedWidth, size.height); canvas.save(); canvas.clipRect(clipRect); paint.color = completedColor; canvas.drawPath(path, paint); canvas.restore(); // 绘制已完成步骤的自定义对勾 final checkmarkPaint = Paint() ..color = checkmarkColor ..style = PaintingStyle.stroke ..strokeWidth = 2.0 ..strokeCap = StrokeCap.round; for (int i = 0; i < completedSteps; i++) { final centerX = i * toothWidth + toothWidth / 2; final centerY = size.height / 2; final checkmarkPath = Path() ..moveTo(centerX - 5, centerY) ..lineTo(centerX - 2, centerY + 4) ..lineTo(centerX + 6, centerY - 6); canvas.drawPath(checkmarkPath, checkmarkPaint); } } @override bool shouldRepaint(covariant SawtoothProgressPainter oldDelegate) { return oldDelegate.completedSteps != completedSteps || oldDelegate.totalSteps != totalSteps; } }
封装成可复用组件
将Painter包装成Widget,方便项目中直接调用:
class SawtoothProgressIndicator extends StatelessWidget { final int totalSteps; final int completedSteps; final double height; final Color completedColor; final Color incompleteColor; final Color checkmarkColor; const SawtoothProgressIndicator({ super.key, required this.totalSteps, required this.completedSteps, this.height = 40.0, this.completedColor = Colors.green, this.incompleteColor = Colors.grey.shade300, this.checkmarkColor = Colors.white, }) : assert(completedSteps <= totalSteps, "完成步骤不能超过总步骤"); @override Widget build(BuildContext context) { return SizedBox( height: height, width: double.infinity, child: CustomPaint( painter: SawtoothProgressPainter( totalSteps: totalSteps, completedSteps: completedSteps, completedColor: completedColor, incompleteColor: incompleteColor, checkmarkColor: checkmarkColor, toothHeight: height * 0.5, toothWidth: (MediaQuery.of(context).size.width) / totalSteps, ), ), ); } }
使用示例
在页面中调用组件,控制进度推进:
class ProgressPage extends StatefulWidget { const ProgressPage({super.key}); @override State<ProgressPage> createState() => _ProgressPageState(); } class _ProgressPageState extends State<ProgressPage> { int _completedSteps = 2; final int _totalSteps = 5; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("锯齿进度指示器")), body: Padding( padding: const EdgeInsets.all(20.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ SawtoothProgressIndicator( totalSteps: _totalSteps, completedSteps: _completedSteps, completedColor: Colors.blue, ), const SizedBox(height: 30), ElevatedButton( onPressed: () { if (_completedSteps < _totalSteps) { setState(() => _completedSteps++); } }, child: const Text("推进进度"), ), ], ), ), ); } }
细节调整说明
- 锯齿的尺寸可通过参数动态修改,适配不同布局
- 对勾路径可调整坐标点,匹配你设计的自定义样式
- 通过
shouldRepaint控制重绘时机,避免不必要的性能消耗
内容的提问来源于stack exchange,提问作者Asfandyar
相关产品推荐
相关产品推荐

