Open giantss opened 2 months ago
The StrokeOrderAnimationController
is a ChangeNotifier
and you can add listeners to it if you like. Listeners get notified whenever any part of the state changes. You should be able to do something like the following:
void listenToAnimationEnding(StrokeOrderAnimationController controller) {
bool wasAnimating = false;
controller.addListener(() {
if (wasAnimating && !controller.isAnimating) {
print('Animation ended');
}
wasAnimating = controller.isAnimating;
});
}
You can use this to react to changes in any of the public attributes of the controller.
Thanks for the reply.
bool wasAnimating = false;
controller.addListener(() {
if (wasAnimating && !controller.isAnimating) {
controller.startQuiz();
}
wasAnimating = controller.isAnimating;
});
controller.startAnimation();
The above code implements the listener after the animation ends. But I don't know why after calling controller.startQuiz();
, the listener will keep calling back until Stack Overflow
appears.
Do you re-register the listener repeatedly? controller.addListener()
should only be called once, for example in initState
and you should dispose of it in dispose
to prevent memory leaks. I can't really tell what's happening from your stack trace, but if you share the code where you register the listener, I might be able to help.
I can be sure that it is only monitored once, because I use Getx to monitor in onInit. Because 111 is only output once. But 222 will be output continuously whether it is during the stroke animation or after the stroke is completed, until Stack Overflow.
@override
void onInit() async {
...
animationController = _loadStrokeOrder(currItemData.words![0].name!);
animationController.then((a){
strokeOrderAnimationController = a;
if(strokeOrderAnimationController != null){
bool wasAnimating = false;
Log.logs("111");
strokeOrderAnimationController!.addListener(() {
Log.logs("222");
if (wasAnimating && !strokeOrderAnimationController!.isAnimating) {
strokeOrderAnimationController!.startQuiz();
}
wasAnimating = strokeOrderAnimationController!.isAnimating;
});
}
});
...
}
logs
I/flutter ( 686): TAG:: 111 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
I/flutter ( 686): TAG:: 222 ::
....
I think you might have some endless loop going on because you call startQuiz
inside the listener and that notifies listeners again. What happens if you replace strokeOrderAnimationController!.startQuiz();
with Log.logs("333");
? Do you still get the stack overflow?
Oh my god, it's really the infinite loop caused by calling strokeOrderAnimationController!.startQuiz();
. But I want to start startQuiz
after the animation is finished. What should I do?
Does wasAnimating && !controller.isAnimating && !controller.isQuizzing
work?
Sorry, I don't quite understand what you mean. My requirement is to start the quiz after the autoplay animation ends.
I tried adding an extra condition && !controller.isQuizzing
to the judgment condition. The Stack Overflow
error no longer appears, but 222 and 333 will still be executed many times.
Okay, so that took care of the endless loop :partying_face:
I am not surprised that the listener gets called multiple times. For example, the controller notifies its listeners when it switches to the next stroke.
How about you replace "222" with something more interesting, like controller.currentStroke
, controller.isAnimating
, and controller.isQuizzing
. That should give you a better feel for when and why the listener gets triggered.
Okay, Are there plans to provide a callback method for when the animation is finished? It would be great if it were possible. Similar to onQuizCompleteCallback
, it will only be triggered once under certain conditions.
That shouldn't be too hard to add, but I don't have a timeline for it. I'll probably add it next time I need to work on this library. Feel free to open a PR though.
Ok, thanks for your reply.
I'll keep this open as a feature request. Thank you for your feedback :)
How do I know that the animation has finished playing after calling
startAnimation
?