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

如何在Flutter中实现与示例图一致的自定义圆形进度指示器

Flutter 自定义圆形旋转进度指示器实现方案

自定义圆形进度指示器示例

我希望在Flutter中实现与示例图完全一致的自定义圆形进度指示器,尝试多种方法仍未成功。我刚接触动画开发,恳请提供帮助或指导。


修正后的完整代码

import 'package:flutter/material.dart';
import 'dart:math';

void main() {
  runApp(const MaterialApp(
    debugShowCheckedModeBanner: false,
    home: Scaffold(
      backgroundColor: Colors.white,
      body: Center(child: RotatingCircularProgress()),
    ),
  ));
}

class RotatingCircularProgress extends StatefulWidget {
  const RotatingCircularProgress({super.key});

  @override
  State<RotatingCircularProgress> createState() => _RotatingCircularProgressState();
}

class _RotatingCircularProgressState extends State<RotatingCircularProgress>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _rotationAnimation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 2),
    )..repeat(); // 无限循环动画

    // 生成0到2π的旋转动画值
    _rotationAnimation = Tween<double>(begin: 0, end: 2 * pi).animate(_controller);
  }

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: 100,
      height: 100,
      child: AnimatedBuilder(
        animation: _rotationAnimation,
        builder: (context, child) {
          return CustomPaint(
            painter: CircularProgressPainter(rotationAngle: _rotationAnimation.value),
          );
        },
      ),
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
}

class CircularProgressPainter extends CustomPainter {
  final double rotationAngle;

  CircularProgressPainter({required this.rotationAngle});

  @override
  void paint(Canvas canvas, Size size) {
    final center = size.center(Offset.zero);
    final radius = size.width / 2 - 5; // 减去一半描边宽度,避免超出容器
    final strokeWidth = 10.0;
    const startAngle = -pi / 2; // 从顶部开始绘制圆弧
    const sweepAngle = 1.7 * pi; // 绘制约3/4圆的弧长

    // 创建渐变,通过旋转矩阵让渐变跟随动画角度变化
    final gradient = SweepGradient(
      colors: [
        Colors.green,                // 起始绿色
        Colors.green.withOpacity(0.7),
        Colors.green.withOpacity(0.4),
        Colors.green.withOpacity(0.1),
        Colors.white,                // 末端白色
      ],
      stops: const [0.0, 0.3, 0.6, 0.85, 1.0],
      tileMode: TileMode.clamp,
      transform: GradientRotation(rotationAngle), // 关联动画旋转角度
    );

    final paint = Paint()
      ..shader = gradient.createShader(Rect.fromCircle(center: center, radius: radius))
      ..style = PaintingStyle.stroke
      ..strokeWidth = strokeWidth
      ..strokeCap = StrokeCap.round; // 圆弧起始端为圆角

    // 绘制固定位置的圆弧,渐变随动画旋转
    canvas.drawArc(
      Rect.fromCircle(center: center, radius: radius),
      startAngle,
      sweepAngle,
      false,
      paint,
    );
  }

  @override
  bool shouldRepaint(covariant CircularProgressPainter oldDelegate) {
    return oldDelegate.rotationAngle != rotationAngle;
  }
}

关键修改说明

  • 动画作用对象调整:不再旋转整个圆弧组件,而是将动画值关联到渐变的GradientRotation变换,让渐变方向随动画旋转,实现示例图中“透明尾部绕圈”的效果
  • 圆弧位置优化:调整radius减去一半描边宽度,避免圆弧超出容器范围;将起始角度设为-pi/2(顶部),更符合常见的圆形指示器起始位置
  • 重绘逻辑修正:shouldRepaint方法对比旋转角度值,只有当动画值变化时才触发重绘,提升性能
  • 渐变关联动画:通过GradientRotation将动画角度传递给渐变,让渐变的过渡区域随动画旋转,完美匹配示例图的动态效果

内容的提问来源于stack exchange,提问作者prabin maharjan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 12:56:06