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.