Keywords: Flutter | Timer | Countdown | Dart | UI Update
Abstract: This article explores methods to create a countdown timer in Flutter that displays time with one decimal precision. It covers using Timer.periodic, CountdownTimer from quiver.async, and the flutter_countdown_timer package, with code examples and best practices for handling button interactions and state updates.
Introduction
In Flutter development, creating a countdown timer that updates in real-time and displays values with decimal precision can be challenging. This article addresses a common scenario where a timer needs to count down from a given duration, rounded to the first decimal place, and update the text of a button child widget. We will explore multiple approaches, including built-in Dart timers and external packages.
Using Timer.periodic for Countdown
The Timer.periodic class from dart:async allows creating a timer that triggers at regular intervals. To implement a countdown timer, we can use it in combination with setState to update the UI. Here's a refined example based on the user's query:
import 'package:flutter/material.dart';
import 'dart:async';
class TimerButton extends StatefulWidget {
final Duration timerDuration;
TimerButton(this.timerDuration);
@override
_TimerButtonState createState() => _TimerButtonState();
}
class _TimerButtonState extends State<TimerButton> {
Timer? _timer;
int _remainingTime; // in milliseconds
@override
void initState() {
super.initState();
_remainingTime = widget.timerDuration.inMilliseconds;
}
void _startTimer() {
const interval = Duration(milliseconds: 100); // Update every 100ms for one decimal
_timer = Timer.periodic(interval, (Timer timer) {
setState(() {
if (_remainingTime <= 100) {
_timer?.cancel();
_remainingTime = 0;
} else {
_remainingTime -= 100;
}
});
});
}
@override
void dispose() {
_timer?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
double seconds = _remainingTime / 1000.0;
String displayText = seconds.toStringAsFixed(1); // Round to one decimal
return RaisedButton(
onPressed: _startTimer,
child: Text(displayText),
);
}
}In this code, the timer updates every 100 milliseconds, decrementing the time and displaying it with one decimal precision. The setState method ensures the UI is rebuilt on each update.
Using CountdownTimer from quiver.async
For a simpler approach, the quiver.async package provides a CountdownTimer class. First, add the dependency to pubspec.yaml:
dependencies:
quiver: ^3.0.0Then, use it in your code:
import 'package:quiver/async.dart';
class CountdownWidget extends StatefulWidget {
@override
_CountdownWidgetState createState() => _CountdownWidgetState();
}
class _CountdownWidgetState extends State<CountdownWidget> {
int _start = 10; // seconds
int _current = 10;
CountdownTimer? _countdownTimer;
void _startTimer() {
_countdownTimer = CountdownTimer(
Duration(seconds: _start),
Duration(seconds: 1),
);
_countdownTimer!.listen(null).onData((duration) {
setState(() {
_current = _start - duration.elapsed.inSeconds;
});
});
_countdownTimer!.listen(null).onDone(() {
print("Done");
_countdownTimer!.cancel();
});
}
@override
void dispose() {
_countdownTimer?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
RaisedButton(
onPressed: _startTimer,
child: Text("Start"),
),
Text("$_current"),
],
);
}
}This method simplifies the timer logic but requires an external package.
Handling Button Click Behavior
To prevent multiple timers from starting on repeated button clicks, you can disable the button or check if a timer is already running. Here's an example using a condition:
void _startTimer() {
if (_timer != null) {
return; // Timer already running, do nothing
}
// Start timer code
}Alternatively, for a restart behavior, cancel the existing timer before starting a new one.
Leveraging the flutter_countdown_timer Package
The flutter_countdown_timer package offers a pre-built widget for countdowns. Add it to pubspec.yaml:
dependencies:
flutter_countdown_timer: ^4.1.0Example usage:
import 'package:flutter_countdown_timer/flutter_countdown_timer.dart';
class MyTimerPage extends StatefulWidget {
@override
_MyTimerPageState createState() => _MyTimerPageState();
}
class _MyTimerPageState extends State<MyTimerPage> {
int endTime = DateTime.now().millisecondsSinceEpoch + 1000 * 30; // 30 seconds from now
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: CountdownTimer(
endTime: endTime,
widgetBuilder: (_, CurrentRemainingTime time) {
if (time == null) {
return Text('Countdown ended');
}
return Text('Seconds: ${time.sec}');
},
),
),
);
}
}This package handles the timer internally and provides customization options.
Conclusion
Implementing a countdown timer in Flutter with decimal precision can be achieved using various methods. Timer.periodic offers flexibility, while external packages like quiver.async and flutter_countdown_timer simplify the process. Always manage timer lifecycle to avoid memory leaks and ensure smooth UI updates.