I have this timer working fine:
Widget timer(int index) {
return Center(
child: AnimatedBuilder(
animation: timerAnimationList[index],
builder: (context, child) {
final double seconds = timerAnimationList[index].value / 1000;
final int integer = seconds.truncate();
final int decimals = (seconds % 1 * 1000).truncate();
String decimalsString = decimals.toString();
switch (decimalsString.length) {
case 1:
decimalsString = '00$decimals';
case 2:
decimalsString = '0$decimals';
}
return Text(
'${integer.toString()}:$decimalsString',
style: const TextStyle(fontSize: 50),
);
},
),
);
It goes from 0 to 10 showing something like 2:453
. When this timer is finished or stopped I show a button to start again. Inside this button, for testing purposes, I only have this:
setState(() {
});
When adding this, the timer cotinues running like if I ran timerControllerList[index].forward()
Why is this happening? I also try to add a unique key to the Text()
showing the timer but it did nothing.
More info: The animator controller is in a List because I have differents timers to play.
class _GamePageState extends State<GamePage> with TickerProviderStateMixin {
List<dynamic> timerControllerList = [];
List<Animation> timerAnimationList = [];
@override
void initState() {
super.initState();
initTimer();
}
void initTimer() {
late AnimationController timerController;
late Animation<int> timerAnimation;
int timerCounter = 10;
timerController = AnimationController(
vsync: this,
duration: Duration(seconds: timerCounter),
);
timerAnimation =
StepTween(begin: 0, end: timerCounter * 1000).animate(timerController)
..addStatusListener((status) {
if (status == AnimationStatus.completed) {
print('TIMER FINISHED');
}
});
timerControllerList.add(timerController);
timerAnimationList.add(timerAnimation);
}
Widgets position:
Stack(
children: [
timer(),
button(),
],
Extra info:
When trying to reproduce this here: https://zapp.run/edit/flutter-zp7q06llp7r0?entry=lib/main.dart&file=lib/main.dart I saw that having a normal button, without any animation and just an onPress with a setState, it doesn't create the same problem. For my case I have something different that I might be conflicting with the other animation:
SlideInUp(
manualTrigger: true,
delay: const Duration(seconds: 2),
controller: (controller) => playAgainButtonController = controller,
child: ElevatedButton...
When timer is stop() I forward() this button to be displayed. Video: https://www.youtube.com/shorts/TlPtGNkyQ5U
This is using this package: https://pub.dev/packages/animate_do (BTW, I installed if last week and popularity was 98% and today it's 76%. How come?)
I just found my issue. Nothing to do with any package, just the way I had my widgets.
So I had something like this:
Widget displayWidgets(int index) {
if (countingDown) return countDown(); // initial countdown before the timer
countingUp = true;
timerControllerList[index].forward();
blackBGControllerList[index].forward();
return timer(index); // actual timer that I mentioned
}
So when I click on the button to update the state and with that some vars like countingUp
I'm triggering the next forward()s as well.
So the solution was to move those 3 lines to the initial countdown that I had before starting the timer (or it could be the initState, for example):
void initCountDown() {
countDownController = AnimationController(
vsync: this,
duration: Duration(seconds: countDownCounter),
);
countDownAnimation =
IntTween(begin: countDownCounter, end: 0).animate(countDownController)
..addStatusListener((status) {
if (status == AnimationStatus.completed) {
setState(() {
countingDown = false;
countingUp = true;
for (var i = 0; i < players; i++) {
timerControllerList[i].forward();
blackBGControllerList[i].forward();
}
countDownController.reset();
});
}
});
countDownController.forward();
}