Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to include Stroke Cap in Sweep Gradient?

Screenshot

You can see my arc starts from top but there is some area which is painted pink, it should be white. I think it is because I am using StrokeCap.round, but how do I remove that part?


Painter class:

class MyPainter extends CustomPainter {
  void paint(Canvas canvas, Size size) {
    double centerPoint = size.height / 2;

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

    paint.shader = SweepGradient(
      colors: [Colors.white, Colors.pink],
      tileMode: TileMode.repeated,
      startAngle: _degreeToRad(270),
      endAngle: _degreeToRad(270 + 360.0),
    ).createShader(Rect.fromCircle(center: Offset(centerPoint, centerPoint), radius: 0));

    double startAngle = _degreeToRad(270);
    double sweepAngle = _degreeToRad(95 / 100 * 360);
    Rect rect = Rect.fromCircle(center: Offset(centerPoint, centerPoint), radius: centerPoint);
    canvas.drawArc(rect, startAngle, sweepAngle, false, paint);
  }

  double _degreeToRad(double degree) => degree * math.pi / 180;

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}

Usage:

CustomPaint(
  size: Size.fromRadius(100),
  painter: MyPainter(),
)
like image 211
iDecode Avatar asked Jan 26 '20 09:01

iDecode


1 Answers

when you are using strokeCap = StrokeCap.round it adds half of the stroke width to start of your line and half of it to the end for creating the round edges of the line so in your calculation you should remove half of the stroke Width from the start and a half of it from end I changed your code and it works as should here is the code:


class MyPainter extends CustomPainter {
  void paint(Canvas canvas, Size size) {
    double centerPoint = size.height / 2;

    double strokeWidth = 30;
    double percentValue=100/100;
    double radius=centerPoint;

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

    paint.shader = SweepGradient(
      colors: [Colors.black, Colors.pink],
      tileMode: TileMode.repeated,
      startAngle: _degreeToRad(270),
      endAngle: _degreeToRad(270 + 360.0),
    ).createShader(Rect.fromCircle(center: Offset(centerPoint, centerPoint), radius: 0));


    Rect rect = Rect.fromCircle(center: Offset(centerPoint, centerPoint), radius: radius);

    var scapSize = strokeWidth / 2;
    double scapToDegree = scapSize / radius;

    double startAngle = _degreeToRad(270)+scapToDegree;
    double sweepAngle = _degreeToRad( 360)-(2*scapToDegree);

    canvas.drawArc(rect, startAngle, percentValue*sweepAngle, false, paint);


  }

  double _degreeToRad(double degree) => degree * pi / 180;

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}

And a performance tip for you :

don't create your shader and gradient each time , the Paint method will be executed numers of time so you should check if you already created the shader for the inComing size use that and don't create it again

like image 135
Amir Hossein Mirzaei Avatar answered Sep 30 '22 19:09

Amir Hossein Mirzaei