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
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.
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
:
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;
}
}