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

如何用Flutter Graphics绘制并旋转圆弧?及实现数值驱动红圆弧动画

Flutter 绘图问题解决方案

1. 绘制圆弧并实现旋转

核心通过CustomPaint配合CustomPainter实现,利用Canvas的旋转API完成圆弧旋转(注意旋转默认绕坐标系原点,需先平移到圆弧中心):

实现步骤

  • 自定义CustomPainter重写paint()方法
  • 用canvas.translate()将坐标系原点移至圆弧中心
  • 调用canvas.rotate()传入旋转弧度(弧度=角度×π/180)
  • 通过canvas.drawArc()绘制圆弧,指定矩形范围、起始角度、扫过角度等参数

代码示例

class RotatingArcPainter extends CustomPainter {
  final double rotationAngle; // 旋转角度(弧度)

  RotatingArcPainter(this.rotationAngle);

  @override
  void paint(Canvas canvas, Size size) {
    final center = Offset(size.width / 2, size.height / 2);
    final radius = min(size.width, size.height) / 2 - 20;
    final rect = Rect.fromCircle(center: center, radius: radius);

    canvas.save();
    // 平移到圆弧中心,避免旋转偏离位置
    canvas.translate(center.dx, center.dy);
    canvas.rotate(rotationAngle);
    canvas.translate(-center.dx, -center.dy);

    final arcPaint = Paint()
      ..color = Colors.blue
      ..style = PaintingStyle.stroke
      ..strokeWidth = 10
      ..strokeCap = StrokeCap.round;

    // 从12点钟方向开始,绘制半圆
    canvas.drawArc(rect, -pi / 2, pi, false, arcPaint);
    canvas.restore();
  }

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

// 页面使用示例
class RotatingArcPage extends StatefulWidget {
  @override
  State<RotatingArcPage> createState() => _RotatingArcPageState();
}

class _RotatingArcPageState extends State<RotatingArcPage> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _rotationAnim;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this,
    )..repeat();
    _rotationAnim = Tween<double>(begin: 0, end: 2 * pi).animate(_controller);
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: CustomPaint(
          size: const Size(300, 300),
          painter: RotatingArcPainter(_rotationAnim.value),
        ),
      ),
    );
  }
}

2. 设计红色进度圆弧并实现数值驱动动画

红色圆弧作为进度指示器,通过数值百分比控制圆弧扫过角度,配合动画实现平滑过渡:

实现思路

  • 进度值范围0~1(如60%对应0.6),扫过角度为2π × 进度值
  • 用AnimationController和Tween实现进度从0到目标值的动画
  • 在CustomPainter中根据当前动画进度绘制红色圆弧,配置描边样式、圆角端点

代码示例

class ProgressArcPainter extends CustomPainter {
  final double progress; // 0~1的进度值

  ProgressArcPainter(this.progress);

  @override
  void paint(Canvas canvas, Size size) {
    final center = Offset(size.width / 2, size.height / 2);
    final radius = min(size.width, size.height) / 2 - 20;
    final rect = Rect.fromCircle(center: center, radius: radius);

    // 绘制背景灰色圆弧
    final bgPaint = Paint()
      ..color = Colors.grey.shade300
      ..style = PaintingStyle.stroke
      ..strokeWidth = 12;
    canvas.drawArc(rect, -pi / 2, 2 * pi, false, bgPaint);

    // 绘制红色进度圆弧
    final progressPaint = Paint()
      ..color = Colors.red
      ..style = PaintingStyle.stroke
      ..strokeWidth = 12
      ..strokeCap = StrokeCap.round;
    // 从12点钟方向开始,按进度绘制圆弧
    canvas.drawArc(rect, -pi / 2, 2 * pi * progress, false, progressPaint);
  }

  @override
  bool shouldRepaint(covariant ProgressArcPainter oldDelegate) {
    return oldDelegate.progress != progress;
  }
}

// 页面使用示例
class ProgressArcPage extends StatefulWidget {
  @override
  State<ProgressArcPage> createState() => _ProgressArcPageState();
}

class _ProgressArcPageState extends State<ProgressArcPage> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _progressAnim;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 1),
      vsync: this,
    );
    // 目标进度60%
    _progressAnim = Tween<double>(begin: 0, end: 0.6).animate(CurvedAnimation(
      parent: _controller,
      curve: Curves.easeInOut,
    ));
    _controller.forward();
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: AnimatedBuilder(
          animation: _progressAnim,
          builder: (context, child) {
            return CustomPaint(
              size: const Size(300, 300),
              painter: ProgressArcPainter(_progressAnim.value),
            );
          },
        ),
      ),
    );
  }
}

内容的提问来源于stack exchange,提问作者Rafhan Chaudhary

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 08:01:25