How to fill in the arcs show in the image only according to the movement of the circular indicator?

164 views Asked by At

The arcs have been drawn using the CustomPainter widget. The drawn widget is used to display the credit score. each arc should be filled as the indicator moves. I have come up with all logic for these but I'm not able to fill in the arcs sequentially.enter image description here

I have used the following code to create the arc background :

// Method to convert degree to radians
num degToRad(num deg) => deg * (math.pi / 180.0);

// Paint
Paint paint = Paint()
  ..color = Grey
  ..style = PaintingStyle.stroke
  ..strokeCap = StrokeCap.round
  ..strokeWidth = 10.0;

// Arc Path
Path path = Path();
path.addArc(Rect.fromLTWH(0, 0, 250, 250), degToRad(180),degToRad(100));
path.addArc(Rect.fromLTWH(0, 0, 250, 250), degToRad(288),degToRad(15));
path.addArc(Rect.fromLTWH(0, 0, 250, 250), degToRad(311),degToRad(15));
path.addArc(Rect.fromLTWH(0, 0, 250, 250), degToRad(334),degToRad(15));
path.addArc(Rect.fromLTWH(0, 0, 250, 250), degToRad(357),degToRad(3));
canvas.drawPath(path, paint);

And for showing the animation of colors I have used the logic below inside the custom painter :

// Paint
Paint paint2 = Paint()
  ..color = Purple
  ..style = PaintingStyle.stroke
  ..strokeCap = StrokeCap.round
  ..strokeWidth = 10.0;


Path path2 = Path();
path2.addArc(Rect.fromLTWH(0, 0, 250, 250), degToRad(180), animationValue);
path2.addArc(Rect.fromLTWH(0, 0, 250, 250), degToRad(288), animationValue2);
path2.addArc(Rect.fromLTWH(0, 0, 250, 250), degToRad(311), animationValue3);
path2.addArc(Rect.fromLTWH(0, 0, 250, 250), degToRad(334), animationValue4);
path2.addArc(Rect.fromLTWH(0, 0, 250, 250), degToRad(357), animationValue5);

canvas.drawPath(path2, paint2);

The following is the logic that i used for the animation:

// First Arc
if (sweepAngleRad >= degToRad(100)) {
  arcAnimation = Tween<double>(begin: 0, end: degToRad(100)).animate(_animationController)
  ..addListener(() {
    setState(() {});
  });
} 
else {
  arcAnimation = Tween<double>(begin: 0, end: sweepAngleRad).animate(_animationController)
  ..addListener(() {
    setState(() {});
  });
}

// Second Arc with delay so as to match with the indicator animation
Future.delayed(Duration(milliseconds: 1150), () {
  if (sweepAngleRad >= degToRad(123)) {
    arcAnimation2 = Tween<double>(begin: 0, end: degToRad(15)).animate(_animationController)
    ..addListener(() {
    setState(() {});
  });
}
else if (sweepAngleRad <= degToRad(108)) {
   arcAnimation2 = Tween<double>(begin: 0, end: 0).animate(_animationController)
  ..addListener(() {
    setState(() {});
  });
} 
else if (sweepAngleRad >= degToRad(108) && sweepAngleRad <= degToRad(115.5)) {
  arcAnimation2 = Tween<double>(begin: 0, end: degToRad(3.75)).animate(_animationController)
  ..addListener(() {
    setState(() {});
  });
}
else if (sweepAngleRad >= degToRad(108) && sweepAngleRad <= degToRad(123)) {
   arcAnimation2 = Tween<double>(begin: 0, end: degToRad(9)).animate(_animationController)
  ..addListener(() {
    setState(() {});
  });
}
});

// Third Arc with delay so as to match with the indicator animation
Future.delayed(Duration(milliseconds: 1300), () {
if (sweepAngleRad >= degToRad(146)) {
  arcAnimation3 = Tween<double>(begin: 0, end: degToRad(15)).animate(_animationController)
  ..addListener(() {
    setState(() {});
  });
}
else if (sweepAngleRad <= degToRad(131)) {
  arcAnimation3 = Tween<double>(begin: 0, end: 0).animate(_animationController)
  ..addListener(() {
    setState(() {});
  });
}
else if (sweepAngleRad >= degToRad(131) && sweepAngleRad <= degToRad(138.5)) {
  arcAnimation3 = Tween<double>(begin: 0, end: degToRad(3.75)).animate(_animationController)
  ..addListener(() {
    setState(() {});
  });
}
else if (sweepAngleRad >= degToRad(131) && sweepAngleRad <= degToRad(146)) {
  arcAnimation3 = Tween<double>(begin: 0, end: degToRad(7.5)).animate(_animationController)
  ..addListener(() {
    setState(() {});
  });
}
});

// Fourth Arc with delay so as to match with the indicator animation
Future.delayed(Duration(milliseconds: 1400), () {
if (sweepAngleRad >= degToRad(169)) {
  arcAnimation4 = Tween<double>(begin: 0, end: degToRad(15)).animate(_animationController)
  ..addListener(() {
    setState(() {});
  });
}
else if (sweepAngleRad <= degToRad(154)) {
  arcAnimation4 = Tween<double>(begin: 0, end: 0).animate(_animationController)
  ..addListener(() {
    setState(() {});
  });
}
 else if (sweepAngleRad >= degToRad(154) && sweepAngleRad <= degToRad(161.5)) {
  arcAnimation4 = Tween<double>(begin: 0, end: degToRad(3.75)).animate(_animationController)
  ..addListener(() {
    setState(() {});
  });
}
else if (sweepAngleRad >= degToRad(154) && sweepAngleRad <= degToRad(169)) {
  arcAnimation4 = Tween<double>(begin: 0, end: degToRad(7.5)).animate(_animationController)
  ..addListener(() {
    setState(() {});
  });
}
});

// Fifth Arc with delay so as to match with the indicator animation
Future.delayed(Duration(milliseconds: 1500), () {
if (sweepAngleRad >= degToRad(177)) {
  arcAnimation5 = Tween<double>(begin: 0, end: degToRad(3)).animate(_animationController)
  ..addListener(() {
    setState(() {});
  });
}
});

and this is how the indicator animation works :

// Convert score to a corresponding angle in between 180-360
if (creditScore == 0) {
  scoreAngle = 180;
  sweepAngleRad = degToRad(1);
} else {
  scoreAngle = 180 + ((creditScore / 850) * 180);
  sweepAngleRad = degToRad(scoreAngle - 180);
}

final initialX = a + (r * math.cos(startAngleRad));
final initialY = b + (r * math.sin(startAngleRad));

Path path = Path();
path.moveTo(initialX, initialY);
path.arcTo(Rect.fromLTWH(0, 0, 250, 250), startAngleRad, sweepAngleRad, true);

Positioned(top: calculate(animation.value).dy,left: calculate(animation.value).dx,
            child: Container(decoration: BoxDecoration(border: Border.all(color: Purple, width: 5.0),shape: BoxShape.circle),
              child: Container(height: 10,width: 10,decoration: BoxDecoration(color: White, shape: BoxShape.circle)))),

Offset calculate(value) {
PathMetrics pathMetrics = _path.computeMetrics();
PathMetric pathMetric = pathMetrics.elementAt(0);
value = pathMetric.length * value;
Tangent pos = pathMetric.getTangentForOffset(value);
return pos.position;
}

Right now the arc's are filling in but not sequentially. I want it to fill in as the indicator moves through the arcs.

0

There are 0 answers