You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 21:09:04