Flutter: How to stop timer after N seconds interval? - flutter

I am using below code to start the timer
Timer Snippet:
_increamentCounter() {
Timer.periodic(Duration(seconds: 2), (timer) {
setState(() {
_counter++;
});
});
}
RaisedButton raisedButton =
new RaisedButton(child: new Text("Button"), onPressed: () {
_increamentCounter();
});
What I all want is to stop this timer after specific(N) timer interval.

Since you want to cancel the Timer after a specific number of intervals and not after a specific time, perhaps this solution is more appropriate than the other answers?
Timer _incrementCounterTimer;
_incrementCounter() {
_incrementCounterTimer = Timer.periodic(Duration(seconds: 2), (timer) {
counter++;
if( counter == 5 ) // <-- Change this to your preferred value of N
_incrementCounterTimer.cancel();
setState(() {});
});
}
RaisedButton raisedButton = new RaisedButton(
child: new Text("Button"),
onPressed: () { _incrementCounter(); }
);

You can use a Future.delayed.
Future.delayed(const Duration(seconds: n), () => _increamentCounter());

Alternatively to Future.delayed(), you can also use
Timer(const Duration(seconds: n), () => _increamentCounter());
The Timer class exposes a couple extra methods like .cancel(), .tick, and isActive, so prefer it if you see yourself needing them down the road.

Related

Flutter: I need help! My random icon pop up animations work but give errors when moving to next page

Map and icons
I have a map and I want to create icons that pop in and fade out after a few
seconds to show that there are other people in the area. These icons generate
random so I call set state to reset their locations, but I am getting errors
when a new page is built. These errors say that my controller was disposed and
then reverse was called and that the null check operator was used on a null
value.
Error Controller disposed then reverse called
Error null check operator used on a null value
Here is my code
late AnimationController _controller1;
late AnimationController _controller2;
late AnimationController _controller3;
Timer? timer1F;
Timer? timer1R;
Timer? timer2F;
Timer? timer2R;
Timer? timer3F;
Timer? timer3R;
#override
void initState() {
super.initState();
_controller1 =
AnimationController(vsync: this, duration: Duration(seconds: 1))
..addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed) {
if (mounted) {
timer1R = Timer(Duration(seconds: 10), () {
_controller1.reverse();
// print('1 Reverse');
timer1F = Timer(Duration(seconds: 30), () {
// setState(() {});
_controller1.forward(from: 0.0);
// print('1 forward');
});
});
}
}
});
_controller1.forward();
_controller2 =
AnimationController(vsync: this, duration: Duration(seconds: 1))
..addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed) {
if (mounted) {
timer2R = Timer(Duration(seconds: 20), () {
_controller2.reverse();
// print('2 Reverse');
timer2F = Timer(Duration(seconds: 20), () {
// setState(() {});
// print('2 forward');
_controller2.forward(from: 0.0);
});
});
}
}
});
// Future.delayed(Duration(seconds: 10), () {
// });
_controller2.forward();
_controller3 =
AnimationController(vsync: this, duration: Duration(seconds: 1))
..addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed) {
if (mounted) {
timer3R = Timer(Duration(seconds: 30), () {
_controller3.reverse();
// print('3 Reverse');
timer3F = Timer(Duration(seconds: 10), () {
// print('3 forward');
setState(() {});
_controller3.forward(from: 0.0);
});
});
}
}
});
_controller3.forward();
}
#override
void dispose() {
_controller1.dispose();
_controller2.dispose();
_controller3.dispose();
timer1F!.cancel();
timer1R!.cancel();
timer2F!.cancel();
timer2R!.cancel();
timer3F!.cancel();
timer3R!.cancel();
super.dispose();
}
Each controller is linked to a different icon, but the error is being called when I reverse the controller. It says it disposes first and then reverse is called. It also shows that if one of the controllers isn't initialized (due to the timer widget calling the controllers forward or reverse) then it gives me that null check assigned to null operator error.

logged out in 30 seconds, unless the user select select Continue

I want to make the user log out in 30 seconds unless the user select Continue
void startTimer() {
Timer(Duration(seconds: 10), () {
logOut(); //It will redirect after 30 seconds
});
}
void logOut() {
Navigator.of(context).pop();
Navigator.of(context, rootNavigator: true)
.pushReplacementNamed(AppRoutes.LOGIN_ROUTE);
}
create a global variable in widget class Timer? _timer
assign it like
_timer = Timer(Duration(seconds: 10), () {
logOut(); //It will redirect after 30 seconds
});
you can cancel the future like
_didUserTapContinue() {
_timer?.cancel();
}
Add a flag that changes state when the continue button is pressed;
bool canContinue = false;
void startTimer() {
Timer(Duration(seconds: 10), () {
if(!canContinue) logOut(); //It will redirect after 30 seconds
});
}
void logOut() {
Navigator.of(context).pop();
Navigator.of(context, rootNavigator: true)
.pushReplacementNamed(AppRoutes.LOGIN_ROUTE);
}
Then set the value of canContinue to true when continue button is pressed

Stopping a function in flutter

I am new to flutter and I have a problem with a flutter function. It adds data to graph and I programmed a button to start updating the graph. How do I stop it? I created another button and I want to program it to stop the function that adds the graph.
The function:
void updateDataSource(Timer timer) {
chartData.add(LiveData(time++, (y)));
chartData.removeAt(0);
_chartSeriesController.updateDataSource(
addedDataIndex: chartData.length - 1, removedDataIndex: 0);
}
The first button:
onPressed: () {
Timer.periodic(const Duration(seconds: 1), updateDataSource);
},
The second button:
onPressed: () {
chartData.clear();
},
I put chartData.clear() but that clears everything and I am unable to call back the function again.
Thanks in advance!
This is due to your Timer.periodic function which is running every second
Solution:
Create a state timer variable
Timer? _timer;
Assign a value to the timer when you first onPressed
onPressed: (){
_timer = Timer.periodic(const Duration(seconds: 1), updateDataSource);
setState((){});
},
And when you want to stop adding graphs Do.
onPressed: () {
if(_timer !=null) {
_timer.cancel();
}
},

Flutter - Using timer to change color of element in gridView() as a sequence

I'm creating a mini-game in my app, which should consist of a grid of 3x3 buttons, which will flash randomly in sequence one-by-one and the user has to recreate it.
I managed to create the buttons with GridView() and set up a timer, but right now I'm struggling with changing the color property of the button inside the GridView(). Which got me thinking If I'm using GridView() correctly.
I want to change the color of a button multiple times via Timer in a random sequence and then the user should recreate it. Can I do it with a timer and GridView()or is there an easier way of doing this?
(My mini-game should be similar to Among us Reactor task)
import 'dart:async';
import 'package:flutter/material.dart';
class Challenge extends StatefulWidget {
#override
_ChallengeState createState() => _ChallengeState();
}
class _ChallengeState extends State<Challenge> {
Timer timer;
Map userData = {};
int indexSaved;
#override
void initState() {
super.initState();
timer = new Timer.periodic(new Duration(seconds: 2), (Timer timer) {
print('hey');
});
}
#override
void dispose() {
super.dispose();
timer.cancel();
}
#override
Widget build(BuildContext context) {
userData = ModalRoute.of(context).settings.arguments;
print(userData);
return Scaffold(
body: SafeArea(
child: Center(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: GridView.count(
crossAxisCount: 3,
// mainAxisSpacing: 20.0,
shrinkWrap: true,
children: List.generate(9, (index) {
return Center(
child: MaterialButton(
color: Colors.blueGrey[300],
padding: EdgeInsets.all(50.0),
splashColor: Colors.white,
onPressed: () {
indexSaved = index;
print(indexSaved);
},
),
);
}),
),
),
),
),
);
}
}
EDIT 21/10/2020:
I created a little function that should generate sequences and I'm launching them inside the timer. I worked on the answers which I got and tried to redo them so I could use them in my use case.
The color I'm changing with:
color: indexWithColor == index
? Colors.indigo
: Colors.blueGrey[300],
which works great.
(The snippet was edited)
List<int> correctValues = [];
int indexWithColor;
int indexDisplayed = 0;
void generateNewLevel() {
final random = new Random(seed);
correctValues.add(random.nextInt(9));
timer = new Timer.periodic(new Duration(milliseconds: 500), (Timer timer) {
setState(() {
indexWithColor = correctValues[indexDisplayed];
// print('Index color ' + indexWithColor.toString());
indexDisplayed++;
if (indexDisplayed == correctValues.length) {
new Timer(new Duration(milliseconds: 500), () {
setState(() {
indexWithColor = null;
indexDisplayed = 0;
});
timer.cancel();
});
timer.cancel();
}
});
});
}
Right now I'm using a button to generate a new level (later I will change it when I solve this problem). It works, but I have issues with it.
Users cannot distinguish if the button is pressed twice (right now its color is pressed for a bit longer).
2. It seems like the buttons have a bit delay when they are launching. It's not exact 500ms and the sleep is really messy.
3. The first level (with a one-long sequence is not visible as it gets changed as soon as the timer is canceled.
Is there a better option?
EDIT: 21/10/2020 12:00pm
I solved the second and third problems with edited timer, so it kinda works right now, but isn't there a better way?
Check the edited snippet. -^
If you want to just randomly change the color of your button this is one way to do it:
(Edited: to make sure that same index isn't selected twice in a row)
final rng = Random();
int indexWithColor;
#override
void initState() {
super.initState();
timer = new Timer.periodic(new Duration(seconds: 2), (Timer timer) {
setState(() {
int tempIndex;
do {
tempIndex = rng.nextInt(9);
} while (tempIndex == indexWithColor);
indexWithColor = tempIndex;
});
});
}
and in your MaterialButton:
color: indexWithColor == index
? Colors.red
: Colors.blueGrey[300],
Yes, you can do it with a Timer. But you need to expand your list with a boolean field which is isIndexSaved.
class NewModel {
int index;
bool isIndexSaved;
}
Then you need to generate a new list with newModel and set isIndexSaved to true when onPressed(). And the color of the MaterialButton should look like:
color: newModel.isIndexSaved
? Colors.red[300], // desired color
: Colors.blueGrey[300],

Is there a way I can continuously change some text in certain interval of time?

In some area, I want a list of objects to be continuously appeared replacing the previous one in a gap of 2 secs. And in that interval I wanna do some logic.
I tried Flutter.delayed but it doesn't work accordingly in a while loop.
In your initState method, use Timer.periodic(...)
#override
void initState() {
super.initState();
// this code runs after every 2 seconds.
Timer.periodic(Duration(seconds: 2), (timer) {
if (_someCondition) {
timer.cancel(); // if you want to stop this loop use cancel
}
setState(() {
_string = "new value"; // your logic here
});
});
}
Create a timer and put your logic in the function that handles the timer event.
...
...
initstate() {
Timer.periodic( Duration(seconds: 2), (Timer t) {
setState(() => displayTheNextElementOfTheList());
...
//your logic here
});
...
}