如何在Flutter中创建支持累计进度、超限计算的自定义圆形进度条
Flutter自定义圆形进度条实现方案
核心实现逻辑
- 基于
CustomPaint组件自主绘制圆形进度,无第三方库依赖,可完全自定义样式 - 内部维护累计进度、最大进度两个状态变量,所有业务逻辑自主可控
- 进度累加逻辑:新增进度值直接追加到累计进度变量,触发状态更新即可同步UI
- 超限处理逻辑:绘制进度时对进度比例做
0~1区间截断保证圆环不会超绘,超出部分直接通过累计进度 - 最大进度计算展示
完整可运行代码
import 'dart:math'; import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: const Text('自定义圆形进度条')), body: const CustomCircleProgress(), ), ); } } class CustomCircleProgress extends StatefulWidget { const CustomCircleProgress({super.key}); @override State<CustomCircleProgress> createState() => _CustomCircleProgressState(); } class _CustomCircleProgressState extends State<CustomCircleProgress> { // 可自定义的最大进度值,按需修改即可 final double _maxProgress = 1200; // 累计进度值 double _currentProgress = 0; final TextEditingController _inputController = TextEditingController(); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.all(20), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // 圆形进度条绘制区域 SizedBox( width: 200, height: 200, child: CustomPaint( painter: CircleProgressPainter( currentProgress: _currentProgress, maxProgress: _maxProgress, bgColor: Colors.grey.shade200, progressColor: Colors.blue, strokeWidth: 12, ), child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( '${_currentProgress.toInt()}/$_maxProgress', style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold), ), if (_currentProgress > _maxProgress) Text( '超出 ${(_currentProgress - _maxProgress).toInt()}', style: const TextStyle(fontSize: 14, color: Colors.red), ), ], ), ), ), ), const SizedBox(height: 40), // 进度输入区域 TextField( controller: _inputController, keyboardType: TextInputType.number, decoration: const InputDecoration( hintText: '请输入要添加的进度值', border: OutlineInputBorder(), ), ), const SizedBox(height: 20), ElevatedButton( onPressed: () { final inputValue = double.tryParse(_inputController.text.trim()); if (inputValue == null || inputValue < 0) return; setState(() { _currentProgress += inputValue; _inputController.clear(); }); }, child: const Text('累加进度'), ), ], ), ); } } // 自定义圆形进度绘制类 class CircleProgressPainter extends CustomPainter { final double currentProgress; final double maxProgress; final Color bgColor; final Color progressColor; final double strokeWidth; CircleProgressPainter({ required this.currentProgress, required this.maxProgress, required this.bgColor, required this.progressColor, required this.strokeWidth, }); @override void paint(Canvas canvas, Size size) { final center = Offset(size.width / 2, size.height / 2); final radius = min(size.width / 2, size.height / 2) - strokeWidth / 2; // 绘制背景圆环 final bgPaint = Paint() ..color = bgColor ..style = PaintingStyle.stroke ..strokeWidth = strokeWidth ..isAntiAlias = true; canvas.drawCircle(center, radius, bgPaint); // 计算进度比例,截断到0~1区间避免超绘 final progressRate = (currentProgress / maxProgress).clamp(0.0, 1.0); // 绘制进度圆环 final progressPaint = Paint() ..color = progressColor ..style = PaintingStyle.stroke ..strokeWidth = strokeWidth ..strokeCap = StrokeCap.round ..isAntiAlias = true; canvas.drawArc( Rect.fromCircle(center: center, radius: radius), -pi / 2, // 起始角度:12点钟方向 2 * pi * progressRate, // 扫过角度 false, progressPaint, ); } @override bool shouldRepaint(covariant CircleProgressPainter oldDelegate) { return oldDelegate.currentProgress != currentProgress || oldDelegate.maxProgress != maxProgress || oldDelegate.bgColor != bgColor || oldDelegate.progressColor != progressColor || oldDelegate.strokeWidth != strokeWidth; } }
功能调整说明
- 自定义最大进度:修改
_maxProgress变量的初始值即可,也可新增输入框实现动态修改最大进度的需求 - 样式调整:可通过修改
CircleProgressPainter的颜色、线宽、圆角等参数,自定义进度条的视觉效果 - 若需要重置进度,新增重置按钮,点击时调用
setState(() => _currentProgress = 0)即可
内容的提问来源于stack exchange,提问作者MD Mosfiqur Rohim Masfiq
相关产品推荐
相关产品推荐

