I'm trying to create a simple widget which counts down from 10 upon getting built. I expected this to start counting down but it remains stuck on 10. Could anyone see what is going wrong here?
class GameTimer extends StatefulWidget {
const GameTimer({
Key? key,
}) : super(key: key);
#override
State<GameTimer> createState() => _GameTimerState();
}
class _GameTimerState extends State<GameTimer> {
initState() {
_startTimer();
}
int _counter = 10;
late Timer _timer;
void _startTimer() {
_counter = 10;
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
setState() {
_counter--;
}
});
}
#override
Widget build(BuildContext context) {
return SizedBox(
child: Text('$_counter',
style: TextStyle(
fontSize: 48,
fontWeight: FontWeight.bold,
)));
}
}
You need to #override before initState and inside it you need to call super.initState()
First of all your initState isnt overriding the super method. so it should be like this:
#override
initState() {
_startTimer();
super.initState();
}
Second, in your _startTimer you are declaring a new function called setState. you missed a couple of parentheses:
setState(() {
_counter--;
});
There are errors in your code
add super.initState(); in init state
seconde your call back function should looks like
setState((){
_counter--;
});
You are almost there !!!!!!
You have missed wrapping the setState callback in parentheses.
Updated code:
class GameTimer extends StatefulWidget {
const GameTimer({
Key? key,
}) : super(key: key);
#override
State<GameTimer> createState() => _GameTimerState();
}
class _GameTimerState extends State<GameTimer> {
initState() {
_startTimer();
}
int _counter = 10;
late Timer _timer;
void _startTimer() {
_counter = 10;
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
setState(() {
_counter--;
});
});
}
#override
Widget build(BuildContext context) {
return SizedBox(
child: Text('$_counter',
style: TextStyle(
fontSize: 48,
fontWeight: FontWeight.bold,
)));
}
}
Related
I have to make a countdown timer for which i have written this code. but it is not updating it's UI even after using setState.
I want to refresh remaining time every second.
class CustomTimer extends StatefulWidget {
final DateTime endtime;
const CustomTimer({Key? key, required this.endtime}) : super(key: key);
#override
State<CustomTimer> createState() => _CustomTimerState();
}
class _CustomTimerState extends State<CustomTimer> {
Timer? timer;
Duration remainTime = Duration();
newTime() {
// print('hi');
setState(() {
final seconds = remainTime.inSeconds - 1;
remainTime = Duration(seconds: seconds);
});
}
#override
void initState() {
remainTime = widget.endtime.difference(DateTime.now());
timer = Timer.periodic(const Duration(seconds: 1), (_) => newTime());
super.initState();
}
#override
void dispose() {
timer?.cancel();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Container(
child: Text(remainTime.toString().split('.')[0].split('')[0] == '-'
? "00:00:00"
: remainTime.toString().split('.')[0]),
);
}
}
I have widgets like those below where one is a child of a container that sometimes has a decoration and sometimes doesnt. For some reason the child is getting recreated instead of just having its build method rerun.
class StatefulReproduction extends StatefulWidget {
const StatefulReproduction({Key? key}) : super(key: key);
#override
_StatefulReproductionState createState() => _StatefulReproductionState();
}
class _StatefulReproductionState extends State<StatefulReproduction>{
var timer;
var counter = 0;
#override
initState() {
print("setup reproduction");
super.initState();
timer = Timer.periodic(new Duration(seconds: 1), (timer) {
setState(() {
counter = 1 + counter;
});
});
}
#override
dispose(){
print("cleaned up reproduction");
super.dispose();
timer.cancel();
}
#override
build(BuildContext context) {
return Container(
child: StatefulChild(),
decoration: BoxDecoration(border: (counter % 2 == 0) ? Border.all(color: const Color.fromARGB(255, 0, 0, 255)): null)
);
}
}
class StatefulChild extends StatefulWidget {
StatefulChild({super.key});
#override
_StatefulChildState createState() => _StatefulChildState();
}
class _StatefulChildState extends State<StatefulWidget>{
#override
initState() {
super.initState();
print("init state called");
}
#override
build(BuildContext context) {
return Text("hi");
}
}
I want the stateful child to only print something once but instead its printing on every time tick which I think means its being recreated but I dont understand why or how I can stop this.
Try to use Border.all(color: Colors.transparent) instead of null. You will not show a border on the screen but initState in the child widget will not be called
Try to add const keyword before the StatefulChild's constructor. And also mark this widget as const inside a Container:
return Container(
child: const StatefulChild(),
decoration: BoxDecoration(border: (counter % 2 == 0) ? Border.all(color: const Color.fromARGB(255, 0, 0, 255)): null)
);
In Flutter, can I put FutureBuilder inside a Timer? Is there a way to automatically refresh the GUI using FutureBuilder? Or any other possible way?
I am not sure what is your goal, but if you want to recreate your widget every X seconds with different strings you can use Future.delayed:
import 'package:flutter/material.dart';
import 'dart:async';
class RefreshWidget extends StatefulWidget {
RefreshWidget({Key? key, required this.title}) : super(key: key);
final String title;
#override
_RefreshWidgetState createState() => _RefreshWidgetState();
}
class _RefreshWidgetState extends State<RefreshWidget> {
static List<String> myStrings = ["aaa", "bbb", "ccc", "ddd"];
int i = 0;
String _current = myStrings[0];
void rebuild() {
Future.delayed(Duration(seconds: 3), () {
setState(() {
_current = myStrings[++i % 4];
});
rebuild();
});
}
#override
void initState() {
rebuild();
super.initState();
}
#override
Widget build(BuildContext context) {
return Material(child: Center(child: Text(_current)));
}
}
This package might help to refresh your widget periodically.
https://pub.dev/packages/refreshable_widget
Flexible(
child: RefreshableWidget<num>(
initialValue: challenge.userParticipation!.donePercent,
refreshCall: () async {
final challenge =
await cadoo.getChallengeDetail(
id: widget.challengeId,
);
return challenge.userParticipation!.donePercent;
},
builder: (context, value) {
return DonePercentWidget(
percent: value,
);
},
),
),
Let's say I am constantly changing the value of a Slider and make some call to a server in the onChanged callback function. Is it possible to change the minimum time period between the callbacks efficiently?
Slider showSoundBar(){
return Slider(
value: this.volume,
activeColor: Colors.blue,
onChanged: (vol){
// Don't send too often
send('volume', vol);
},
);
}
You could do something like this using a Timer from dart:async..
class MyWidget extends StatefulWidget {
#override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
Timer timer;
int timePassedInMilliseconds = 1500;
#override
void initState(){
super.initState();
timer = Timer.periodic(Duration(milliseconds: 100), (_){
timePassedInMilliseconds = timePassedInMilliseconds + 100;
});
}
#override
Widget build(BuildContext context) {
return Slider(
value: 10,
activeColor: Colors.blue,
onChanged: (vol){
// Don't send too often
if(timePassedInMilliseconds > 1500){
send('volume', vol);
timePassedInMilliseconds = 0;
}
},
);
}
void send(String sendWhat, double value){
}
#override
void dispose(){
timer.cancel();
super.dispose();
}
}
I've created a screen in Flutter that displays a countdown timer. I'm able to play, pause and restart the timer, but I am trying to figure out how to perform an action when the timer reaches 0 (for example, restart itself).
As the dart file is fairly lengthy, I'm just copying below what I believe to be the relevant portions here. But I can add more if needed.
First I create a widget/class for the countdown timer:
class Countdown extends AnimatedWidget {
Countdown({ Key key, this.animation }) : super(key: key, listenable: animation);
Animation<int> animation;
#override
build(BuildContext context){
return Text(
animation.value.toString(),
style: TextStyle(
fontSize: 120,
color: Colors.deepOrange
),
);
}
}
I then have a stateful widget which creates the controller and also imports some data (gameData.countdownClock is the countdown timer's start time, it comes from user input at an earlier screen):
class _GameScreenState extends State<GameScreen> with TickerProviderStateMixin {
AnimationController _controller;
_GameScreenState(this.gameData);
GameData gameData;
#override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(seconds: gameData.countdownClock),
);
}
And then the container that displays the clock:
Container(
child: Countdown(
animation: StepTween(
begin: gameData.countdownClock,
end: 0,
).animate(_controller),
),
),
Do I have to add a listener in that last container? Or somewhere else? (Or something else entirely!)
Any help is appreciated. Thank you
I found the answer on this page:
After complete the widget animation run a function in Flutter
I needed to add .addStatusListener to the animation controller in the initState().
So the new initState() code looks like this:
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(seconds: gameData.countdownClock),
);
_controller.addStatusListener((status){
if(status == AnimationStatus.completed){
_controller.reset();
}
}
);
}
Possible value of Animation controller is between 0 to 1.
So I think you have to add listener on gamedata.countDownClock
Please check the below code you might get some idea from it.
import 'dart:async';
import 'package:flutter/material.dart';
class GameScreen extends StatefulWidget {
#override
_GameScreenState createState() => _GameScreenState();
}
class _GameScreenState extends State<GameScreen> with SingleTickerProviderStateMixin {
int countdownClock = 10;
#override
void initState() {
super.initState();
// Your Game Data Counter Change every one Second
const oneSec = const Duration(seconds:1);
new Timer.periodic(oneSec, (Timer t) {
// Restart The Counter Logic
if (countdownClock == 0)
countdownClock = 11;
setState(() { countdownClock = countdownClock - 1; });
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("")),
body: Center(
child: Text('$countdownClock')
),
);
}
}