How to render a arc path after previous arc animation complete

614 views Asked by At

When I trying to render a two arc in I same path both are rendered at the same time, but I need to render a second arc after the first arc's animation gets completed.

I just want to render the second arc as it should start from the end of the first arc and complete the rest of the animation (continuous animation).

Expected results Actual results

I have attached the code snippet below, can anyone please help me with this.

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: Circle(),
      ),
    );
  }
}

class Circle extends StatefulWidget {
  @override
  _CircleState createState() => _CircleState();
}

class _CircleState extends State<Circle> with SingleTickerProviderStateMixin {
  double? _fraction = 0.0;
  late Animation<double> _animation;
  late AnimationController _controller;
  @override
  void initState() {
    super.initState();

    _controller =
        AnimationController(duration: Duration(milliseconds: 5000), vsync: this);

    _animation = Tween(begin: 0.0, end: 1.0).animate(_controller)
      ..addListener(() {
        setState(() {
          _fraction = _animation.value;
        });
      });

    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Center(
        child: Padding(
            padding: const EdgeInsets.all(24.0),
            child: CustomPaint(
              painter: CirclePainter(fraction: _fraction!),
            ),
          ),
      ),
    );
  }

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

class CirclePainter extends CustomPainter {
  final double? fraction;
  late Paint _circlePaint;

  CirclePainter({this.fraction}) {
    _circlePaint = Paint()
      ..color = Colors.red
      ..style = PaintingStyle.fill;
  }
  final Paint _paint = Paint()
  ..color = Colors.black
  ..style = PaintingStyle.stroke
  ..strokeWidth = 3;

  @override
  void paint(Canvas canvas, Size size) {
    final Path path = Path();
    path.addArc(
      Rect.fromCircle(center: Offset(size.width/2, size.height/2), radius: 131.0909090909091),
      _degreesToRadians(-90).toDouble(), (_degreesToRadians(269.999 * fraction!).toDouble() - _degreesToRadians(-90).toDouble()));
    path.arcTo(
      Rect.fromCircle(center: Offset(size.width/2, size.height/2), radius: 42.32727272727273),
     _degreesToRadians(269.999 * fraction!).toDouble(), _degreesToRadians(-90).toDouble() - _degreesToRadians((269.999) * fraction!).toDouble(),
      false);
    path.addArc(
      Rect.fromCircle(center: Offset(size.width/2, size.height/2), radius: 131.0909090909091),
      _degreesToRadians(-90).toDouble(), (_degreesToRadians(179.999 * fraction!).toDouble() - _degreesToRadians(-90).toDouble()));
    path.arcTo(
      Rect.fromCircle(center: Offset(size.width/2, size.height/2), radius: 42.32727272727273),
     _degreesToRadians(179.999 * fraction!).toDouble(), _degreesToRadians(-90).toDouble() - _degreesToRadians((179.999) * fraction!).toDouble(),
      false);
  canvas.drawPath(path, _circlePaint);
  canvas.drawPath(path, _paint);
  }

  @override
  bool shouldRepaint(CirclePainter oldDelegate) {
    return oldDelegate.fraction != fraction;
  }
}
num _degreesToRadians(num deg) => deg * (pi / 180);

Expected :

1

There are 1 answers

2
Igniti0n On

You can do it like this, where the first angle is the start angle, and the second angle is the end angle. You can adjust other things as you wish, but to get the effect of spinning you keep changing the end angle.

I you don't want for the tip to be round you can put StrokeCap.butt

The library for this radians function is vector_math.

 _path.addArc(Rect.fromLTWH(0, 0, size.width, size.height), vm.radians(-90),
        vm.radians(90));

    canvas.drawPath(
        _path,
        Paint()
          ..strokeCap = StrokeCap.round
          ..strokeWidth = 40
          ..style = PaintingStyle.stroke);

And for the second one to start after the other, you can again use the same concept as I wrote in above code, in combination with staggered animation.

 final Animation<double> firstAnimation=
        Tween<double>(begin: 0, end: 1).animate(CurvedAnimation(
      parent: animationController,
      curve: Interval(0, 0.5, curve: Curves.easeIn),
    ));

final Animation<double> secondAnimation=
        Tween<double>(begin: 0, end: 1).animate(CurvedAnimation(
      parent: animationController,
      curve: Interval(0.5, 1, curve: Curves.easeIn),
    ));