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]),
);
}
}
Related
I have an issue with the auto dispose change notifier provider
I have created a widget to handle screen state to init data then show loading and after loading the screen will appear.
class ConsumerHelper extends StatefulWidget {
const ConsumerHelper({
super.key,
this.onInit,
this.onDispose,
this.onReady,
required this.child,
});
final Widget child;
final Future? onInit;
final VoidCallback? onDispose;
final VoidCallback? onReady;
#override
State<StatefulWidget> createState() => _ConsumerHelperState();
}
class _ConsumerHelperState extends State<ConsumerHelper> {
bool isLoading = true;
#override
void initState() {
Future.microtask(() async {
if (widget.onInit != null) {
await widget.onInit!;
if (widget.onReady != null) {
widget.onReady!();
}
}
isLoading = false;
if (mounted) {
setState(() {});
}
});
super.initState();
}
#override
void dispose() {
if (widget.onDispose != null) {
widget.onDispose!();
}
super.dispose();
}
#override
Widget build(BuildContext context) {
if (isLoading) {
return const Material(child: LoadingWidget());
} else {
return widget.child;
}
}
}
But when I'm using ref.read in the ConsumerHelper onInit parameter then use ref.watch inside the new ConsumerHelper child it throws an error
A was used after being disposed. Once you have called dispose() on A, it can no longer be used
here is how i use the ConsumerHelper Widget
class CategoriesPage extends ConsumerWidget {
const CategoriesPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context, ref) {
final controller = ref.read(categoriesProvider);
return WillPopScope(
onWillPop: () async {
ref.read(pagesHandlerProvider.notifier).setIndex = 0;
return false;
},
child: ConsumerHelper(
onInit: controller.getCategories(),
child: Scaffold(
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,
)));
}
}
Trying to Navigate back and forth between SignIn and ForgotPassword Page using Navigation.push().
But the Forgot Password Page Keep Losing its state (the countdown timer here).
Home Page for App. Home
When I enter email it shows a message and a counter (goes from 30 to 0). Page State
I go back to SignIn page and come back the timer and message are gone. State Gone
How to save a state for Navigation.push() page?
Forgot.dart
class ForgotPassword extends StatefulWidget {
const ForgotPassword({Key? key}) : super(key: key);
#override
_ForgotPasswordState createState() => _ForgotPasswordState();
}
class _ForgotPasswordState extends State<ForgotPassword> {
TextEditingController emailC = TextEditingController();
final formkey = GlobalKey<FormState>();
AuthMethods authMethods = AuthMethods();
bool sent = false;
Timer? _timer;
int _start = 0;
void startTimer() async {
if (formkey.currentState!.validate() && _start == 0) {
_start = 30;
const oneSec = const Duration(seconds: 1);
_timer = new Timer.periodic(
oneSec,
(Timer timer) {
if (_start == 0) {
setState(() {
timer.cancel();
});
} else {
setState(() {
_start--;
});
}
},
);
await authMethods.resetPassword(emailC.text);
}
}
#override
void dispose() {
_timer!.cancel();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(... rest of code
body: PageView(
controller: _pageController,
physics: NeverScrollableScrollPhysics(),
children: [
FirstScreen(),
SecondScreen(),
],
),
replace Navigator.push()/pop() with _pageController.goToPage(0 or 1)
this my code
Container(
child: Column(
children: jobProvider.jobs
.map(
(job) => JobTile(job),
)
.toList(),
),
)
how to load this data delay for 3 seconds ? here I display the listview data, before displaying it I want to display, the
return Container(
child: ProfileShimmer(),
);
Should be as easy as this:
import 'package:flutter/material.dart';
class PageWithDelayedView extends StatefulWidget {
const PageWithDelayedView({Key? key}) : super(key: key);
#override
_PageWithDelayedViewState createState() => _PageWithDelayedViewState();
}
class _PageWithDelayedViewState extends State<PageWithDelayedView> {
bool _initialized = false;
#override
void initState() {
super.initState();
// Schedule function call after the widget is ready to display
WidgetsBinding.instance?.addPostFrameCallback((_) {
_initialize();
});
}
void _initialize() {
Future<void>.delayed(const Duration(seconds: 3), () {
if (mounted) { // Check that the widget is still mounted
setState(() {
_initialized = true;
});
}
});
}
#override
Widget build(BuildContext context) {
if (!_initialized) {
return Text('Hold on a bit');
}
return Text('Yay, I\'m ready!');
}
}
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();
}
}