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

Flutter如何实现带中心文字的自定义圆形进度指示器?

在Flutter中实现带中心文本的自定义圆形进度指示器

嗨,我来帮你搞定这个需求~原生的CircularProgressIndicator确实不支持直接在中心加文本,但我们可以通过叠加组件或者自定义绘制两种方式轻松实现,下面给你详细讲两种方案:

方法一:基于原生组件快速实现(低成本)

这种方式最省心,直接用Stack把原生进度圈和文本叠在一起,保留原生组件的样式特性:

class TextCircularProgress extends StatelessWidget {
  final double progress; // 0-1的进度值
  final String centerText;
  final Color? progressColor;
  final double strokeWidth;
  final TextStyle? textStyle;

  const TextCircularProgress({
    super.key,
    required this.progress,
    required this.centerText,
    this.progressColor,
    this.strokeWidth = 4.0,
    this.textStyle,
  });

  @override
  Widget build(BuildContext context) {
    return Stack(
      alignment: Alignment.center, // 让文本居中在进度圈上
      children: [
        // 原生圆形进度指示器
        CircularProgressIndicator(
          value: progress,
          strokeWidth: strokeWidth,
          valueColor: progressColor != null
              ? AlwaysStoppedAnimation(progressColor!)
              : null,
          backgroundColor: Colors.grey.shade200,
        ),
        // 中心文本
        Text(
          centerText,
          style: textStyle ?? const TextStyle(
            fontSize: 16,
            fontWeight: FontWeight.bold,
            color: Colors.black87,
          ),
        ),
      ],
    );
  }
}

使用示例

// 显示60%的进度
TextCircularProgress(
  progress: 0.6,
  centerText: "60%",
  progressColor: Colors.blue,
  strokeWidth: 6.0,
)

方法二:自定义Painter实现高度定制

如果需要更个性化的效果(比如进度条圆角、渐变颜色、特殊轨迹),可以用CustomPainter完全自定义绘制逻辑:

class CustomTextProgressCircle extends StatefulWidget {
  final double progress;
  final String centerText;
  final Color progressColor;
  final Color bgColor;
  final double strokeWidth;
  final TextStyle textStyle;

  const CustomTextProgressCircle({
    super.key,
    required this.progress,
    required this.centerText,
    this.progressColor = Colors.green,
    this.bgColor = Colors.grey.shade300,
    this.strokeWidth = 8.0,
    required this.textStyle,
  });

  @override
  State<CustomTextProgressCircle> createState() => _CustomTextProgressCircleState();
}

class _CustomTextProgressCircleState extends State<CustomTextProgressCircle> {
  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      painter: _ProgressCirclePainter(
        progress: widget.progress,
        progressColor: widget.progressColor,
        bgColor: widget.bgColor,
        strokeWidth: widget.strokeWidth,
      ),
      child: Center(child: Text(widget.centerText, style: widget.textStyle)),
    );
  }
}

// 自定义绘制逻辑
class _ProgressCirclePainter extends CustomPainter {
  final double progress;
  final Color progressColor;
  final Color bgColor;
  final double strokeWidth;

  _ProgressCirclePainter({
    required this.progress,
    required this.progressColor,
    required this.bgColor,
    required this.strokeWidth,
  });

  @override
  void paint(Canvas canvas, Size size) {
    final center = Offset(size.width / 2, size.height / 2);
    final radius = (size.width - strokeWidth) / 2;

    // 绘制背景圆环
    final bgPaint = Paint()
      ..color = bgColor
      ..style = PaintingStyle.stroke
      ..strokeWidth = strokeWidth
      ..strokeCap = StrokeCap.round; // 进度条两端设为圆角
    canvas.drawCircle(center, radius, bgPaint);

    // 绘制进度圆环
    final progressPaint = Paint()
      ..color = progressColor
      ..style = PaintingStyle.stroke
      ..strokeWidth = strokeWidth
      ..strokeCap = StrokeCap.round;
    final arcAngle = 2 * pi * progress;
    canvas.drawArc(
      Rect.fromCircle(center: center, radius: radius),
      -pi / 2, // 从顶部开始绘制(默认是右侧)
      arcAngle,
      false,
      progressPaint,
    );
  }

  @override
  bool shouldRepaint(_ProgressCirclePainter oldDelegate) {
    return oldDelegate.progress != progress ||
        oldDelegate.progressColor != progressColor ||
        oldDelegate.strokeWidth != strokeWidth;
  }
}

使用示例

CustomTextProgressCircle(
  progress: 0.75,
  centerText: "75%",
  progressColor: Colors.orange,
  bgColor: Colors.grey.shade200,
  strokeWidth: 10.0,
  textStyle: const TextStyle(
    fontSize: 22,
    fontWeight: FontWeight.w600,
    color: Colors.deepOrange,
  ),
)

两种方案任选其一就行,第一种适合快速开发,第二种适合需要个性化样式的场景~

内容的提问来源于stack exchange,提问作者Musa Usman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:25:03