简体   繁体   English

Flutter 圆形进度指示器-可重复-定制画家

[英]Flutter circular progress indicator - repeatable-Custom painter

I want to create something like that: Want to achieve我想创造这样的东西:想要实现

I have achieved this: Done up until now我已经做到了:到现在为止

I am struggling to add just vertical line at state of this circular progress bar just like the line at trailing.我正在努力在这个圆形进度条的 state 处添加垂直线,就像尾随处的线一样。

import 'dart:math';

import 'package:flutter/material.dart';

class LoaderPaint extends CustomPainter {
  final double percentage;
  LoaderPaint({
    required this.percentage,
  });

  deg2Rand(double deg) => deg * pi / 180;

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

    final paint = Paint()
      ..strokeCap = StrokeCap.round
      ..color = Colors.white
      ..style = PaintingStyle.stroke
      ..strokeWidth = 2;

    canvas.drawLine(
      Offset(midOffset.dy, 10),
      Offset(midOffset.dy,-10),
      paint,
    );
    canvas.drawArc(
      Rect.fromCenter(center: midOffset, width: size.width, height: size.height),
      deg2Rand(-90),
      deg2Rand(360 * percentage),
      false,
      paint,
    );

  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true;
  }
}
  1. Calculate the end position of the line by using the formula found in this stackoverflow answer .使用此stackoverflow 答案中的公式计算行的末尾 position。 Since we start the angle at -90 degrees we must take that away from the sweepAngle.由于我们从 -90 度开始角度,因此我们必须将其从 sweepAngle 中移开。

  2. Calculate the points 10 units before and after the end position of the line using the formula in this answer , plugging in the center of the circle and the end position of the line.使用此答案中的公式计算直线末端 position 前后 10 个单位的点,插入圆心和直线末端 position。

  3. Draw the line with canvas.drawLinecanvas.drawLine画线

Here is what your updated LoaderPaint class looks like with these changes:以下是更新后的LoaderPaint class 与这些更改后的样子:

class LoaderPaint extends CustomPainter {
  final double percentage;
  const LoaderPaint({
    required this.percentage,
  });

  deg2Rand(double deg) => deg * pi / 180;

  @override
  void paint(Canvas canvas, Size size) {
    final radius = size.width / 2;
    final sweepAngle = deg2Rand(360 * percentage);
    final theta = deg2Rand(-90) + sweepAngle;
    
    final midOffset = Offset(radius, radius);
    final endOffset = Offset(radius + radius * cos(theta), radius + radius * sin(theta));
    
    final midEndDiff = sqrt(pow(endOffset.dx - midOffset.dx, 2) + pow(endOffset.dy - midOffset.dy, 2));

    final paint = Paint()
      ..strokeCap = StrokeCap.round
      ..color = Colors.white
      ..style = PaintingStyle.stroke
      ..strokeWidth = 2;

    canvas.drawLine(
      Offset(midOffset.dy, 10),
      Offset(midOffset.dy,-10),
      paint,
    );
    canvas.drawArc(
      Rect.fromCenter(center: midOffset, width: size.width, height: size.height),
      deg2Rand(-90),
      sweepAngle,
      false,
      paint,
    );
    canvas.drawLine(
      Offset(endOffset.dx + (10/midEndDiff) * (endOffset.dx - midOffset.dx), endOffset.dy + (10/midEndDiff) * (endOffset.dy - midOffset.dy)),
      Offset(endOffset.dx - (10/midEndDiff) * (endOffset.dx - midOffset.dx), endOffset.dy - (10/midEndDiff) * (endOffset.dy - midOffset.dy)),
      paint,
    );

  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true;
  }
}

This dartpad shows it working.这个 dartpad显示它工作正常。 You can easily change the percentage to see it work at all angles.您可以轻松更改百分比以查看它在各个角度的工作情况。

You must bear in mind this will only work if the width and height of the CustomPaint widget are exactly the same, however your example without the end cap would also break if the width and height were different.您必须记住,这仅在CustomPaint小部件的宽度和高度完全相同的情况下才有效,但是如果宽度和高度不同,您的没有端盖的示例也会中断。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM