Issue
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.
Solution
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
: sign
Trigonometry
I suppose the sample you posted is much simpler than your real code and the simplifications hereafter are probably not meaningful.
However, pay attention that near zero calculus on computers is quite messy!
import 'dart:math';
void main() {
print(' sin(0).sign: ${sin(0).sign}');
print(' sin(0).sign: ${sin(0).sign}');
print('------------------------------------------');
print(' sin(180*pi/180): ${sin(180*pi/180)}');
print('!! sin(180*pi/180).sign: ${sin(180*pi/180).sign}');
}
sin(0).sign: 0
sin(0).sign: 0
------------------------------------------
sin(180*pi/180): 1.2246467991473532e-16
!! sin(180*pi/180).sign: 1
Full example after correction and simplification
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;
}
}
Answered By - Thierry
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.