Home > Mobile >  Flutter trigonometry animation elements not reaching their desired positions at the same time
Flutter trigonometry animation elements not reaching their desired positions at the same time

Time:02-23

The animation begins like this, with both circles in the center, but ends up where one circle reaches the end faster for some reason. How could I make it so that they reach the ends at the same time? I don't understand why this code isn't working. Any help would be much appreciated, thank you!

  @override
  void paint(Canvas canvas, Size size) {
    var percentFinished = _animation.value;
    var middleY = size.height / 2;
    var middleX = size.width / 2;
    double radius = 40;

    var angles = [180, 0];

    for (var angle in angles) {
      var radians = (angle * pi) / 180;
      var endingX = middleX   cos(radians) * radius;
      var endingY = middleY - sin(radians) * radius;
      var addToY = negativeOrPositiveOrZero(sin(radians)) * percentFinished;
      var addToX = negativeOrPositiveOrZero(cos(radians)) * percentFinished;

      canvas.drawCircle(Offset(endingX * addToX   middleX, endingY * addToY   middleY), 10, Paint());
    }
  }

  int negativeOrPositiveOrZero(double a) {
    int num = a.toInt();
    if (num > 0){
      print("1"   ": "   num.toString());
      return 1;
    }
    else if (num < 0) {
      return -1;
    }
    else {
      return 0;
    }
  }

Below is just some screenshots of what I'm talking about.

The animation starts like this, with two balls in the center

animation start

But it ends in this state where one circle reaches the end before the other. The desired behavior is to have them reach their side of the screen at the same time.

end of animation

CodePudding user response:

I think your problem is how you compute your endingX.

var endingX = middleX   cos(radians) * radius;

It seems that your endingX should be the distance between the side of the Canvas and the perimeter of the Circles in their initial position. It's, therefore, the same for both directions:

var endingX = middleX - radius;

Then, a few simplifications on your code:

negativeOrPositiveOrZero

You have a getter for that in dart:math: enter image description here

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Rolling balls',
      home: Scaffold(
        body: Center(
          child: Container(
            width: 300,
            height: 200,
            color: Colors.amber.shade300,
            child: const MyCustomPaint(),
          ),
        ),
      ),
    );
  }
}

class MyCustomPaint extends StatefulWidget {
  const MyCustomPaint({Key? key}) : super(key: key);

  @override
  _MyCustomPaintState createState() => _MyCustomPaintState();
}

class _MyCustomPaintState extends State<MyCustomPaint>
    with SingleTickerProviderStateMixin {
  late Animation<double> _animation;
  late AnimationController _controller;

  @override
  void initState() {
    super.initState();

    _controller = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 4),
    );

    Tween<double> _animationTween = Tween(begin: 0.0, end: 1.0);

    _animation = _animationTween.animate(_controller)
      ..addListener(() => setState(() {}))
      ..addStatusListener((status) {
        if (status == AnimationStatus.completed) {
          _controller.reverse();
        } else if (status == AnimationStatus.dismissed) {
          _controller.forward();
        }
      });
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      painter: MyCustomPainter(_animation.value),
    );
  }
}

class MyCustomPainter extends CustomPainter {
  final double percentFinished;

  MyCustomPainter(this.percentFinished);

  @override
  void paint(Canvas canvas, Size size) {
    double middleY = size.height / 2;
    double middleX = size.width / 2;
    double radius = size.width / 20;

    Paint paint = Paint()..color = Colors.black;

    for (int direction in [1, -1]) {
      var endingX = middleX - radius;
      var addToX = direction * percentFinished;
      canvas.drawCircle(
        Offset(endingX * addToX   middleX, middleY),
        radius,
        paint,
      );
    }
  }

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