I have a periodic timer and i'm trying to call some methods when it started. But the problem is when i press the inkwell a few times in a row and wait the program 2 seconds for restart the timer. The timer speeds up..
I'm trying to solve it for a while but i doesn't work. I hope it was clear for you to understand. Thanks.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:wordgame/controller.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(title: 'Material App', home: MyWidget());
}
}
class MyWidget extends StatefulWidget {
const MyWidget({super.key});
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
@override
void initState() {
startTimer();
super.initState();
}
late Duration duration;
Timer? timer;
void startTimer() {
duration = Duration(seconds: 5);
myController.selectMainWord();
myController.selectValueWords();
myController.selectedIndex = -1;
timer = Timer.periodic(Duration(seconds: 1), (timer) {
if (duration.inSeconds > 0) {
duration -= Duration(seconds: 1);
print(duration.inSeconds.toString());
} else {
duration = Duration(seconds: 5);
}
setState(() {});
});
}
cancelTimer() {
timer?.cancel();
timer = null;
}
MyController myController = MyController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
children: [
Container(
child: Text(
myController.mainWord,
style: TextStyle(fontSize: 36),
),
),
Expanded(
child: GridView.builder(
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200,
childAspectRatio: 3 / 2,
crossAxisSpacing: 20,
mainAxisSpacing: 20),
itemCount: myController.valueWordList.length,
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: () async {
myController.selectedIndex = index;
setState(() {
timer?.cancel();
});
await Future.delayed(Duration(seconds: 2));
startTimer();
},
child: Container(
color: myController.isRightWord(index) &&
myController.selectedIndex == index
? Colors.green
: Colors.blue,
alignment: Alignment.center,
child: Text(
myController.valueWordList[index],
style: TextStyle(fontSize: 36),
),
),
);
},
),
),
Container(
child: Text(duration.inSeconds.toString()),
)
],
),
);
}
}
When tapping, you are indeed canceling the timer, but you cannot stop the previous onTap callback execution, which will call startTimer creating a new timer internally. This will lead to multiple timers kicking off, resulting in the sped-up count-down.
Since we cannot interrupt an async opertaion, we need to cancel it before it even starts, and here comes the debounce pattern for the rescue: