Created
November 15, 2024 08:29
-
-
Save tejaswini-dev-techie/f484e6f0f7bd703f2036e499f928d48c to your computer and use it in GitHub Desktop.
Building a Countdown Timer in Flutter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import 'dart:async'; | |
| import 'package:flutter/material.dart'; | |
| void main() { | |
| runApp(const MyApp()); | |
| } | |
| class MyApp extends StatelessWidget { | |
| const MyApp({Key? key}) : super(key: key); | |
| @override | |
| Widget build(BuildContext context) { | |
| return MaterialApp( | |
| title: 'Flutter Demo', | |
| theme: ThemeData( | |
| primarySwatch: Colors.deepPurple, | |
| ), | |
| home: const TimerScreen(), | |
| ); | |
| } | |
| } | |
| class TimerScreen extends StatefulWidget { | |
| const TimerScreen({Key? key}) : super(key: key); | |
| @override | |
| _TimerScreenState createState() => _TimerScreenState(); | |
| } | |
| class _TimerScreenState extends State<TimerScreen> { | |
| static const Duration countdownDuration = Duration(minutes: 0, seconds: 10); | |
| final ValueNotifier<Duration> durationNotifier = | |
| ValueNotifier<Duration>(countdownDuration); | |
| Timer? timer; | |
| @override | |
| void initState() { | |
| super.initState(); | |
| startTimer(); | |
| } | |
| @override | |
| void dispose() { | |
| timer?.cancel(); | |
| durationNotifier.dispose(); | |
| super.dispose(); | |
| } | |
| void startTimer() { | |
| timer = Timer.periodic(const Duration(seconds: 1), (_) => addTime()); | |
| } | |
| void addTime() { | |
| final seconds = durationNotifier.value.inSeconds - 1; | |
| if (seconds < 0) { | |
| timer?.cancel(); | |
| // Handle end of timer here | |
| showEndMessage(); | |
| } else { | |
| durationNotifier.value = Duration(seconds: seconds); | |
| } | |
| } | |
| void showEndMessage() { | |
| showDialog( | |
| context: context, | |
| builder: (BuildContext context) { | |
| return AlertDialog( | |
| title: const Text("Timer Ended"), | |
| content: const Text("The timer has ended."), | |
| actions: <Widget>[ | |
| TextButton( | |
| child: const Text("OK"), | |
| onPressed: () { | |
| Navigator.of(context).pop(); | |
| }, | |
| ), | |
| ], | |
| ); | |
| }, | |
| ); | |
| } | |
| @override | |
| Widget build(BuildContext context) { | |
| return WillPopScope( | |
| onWillPop: _onWillPop, | |
| child: Scaffold( | |
| backgroundColor: const Color(0xFFadd8e6), | |
| body: Center( | |
| child: ValueListenableBuilder<Duration>( | |
| valueListenable: durationNotifier, | |
| builder: (context, duration, child) { | |
| return Column( | |
| mainAxisAlignment: MainAxisAlignment.center, | |
| children: [ | |
| buildTime(duration), | |
| if (duration.inSeconds <= 0) // Show "END" when timer is zero or less | |
| const Padding( | |
| padding: EdgeInsets.only(top: 20.0), | |
| child: Text( | |
| "END", | |
| style: TextStyle( | |
| color: Colors.white, | |
| fontSize: 36, | |
| fontWeight: FontWeight.bold, | |
| ), | |
| ), | |
| ), | |
| ], | |
| ); | |
| }, | |
| ), | |
| ), | |
| ), | |
| ); | |
| } | |
| Future<bool> _onWillPop() async { | |
| timer?.cancel(); | |
| Navigator.of(context).pop(); | |
| return true; | |
| } | |
| Widget buildTime(Duration duration) { | |
| String twoDigits(int n) => n.toString().padLeft(2, '0'); | |
| final hours = twoDigits(duration.inHours); | |
| final minutes = twoDigits(duration.inMinutes.remainder(60)); | |
| final seconds = twoDigits(duration.inSeconds.remainder(60)); | |
| return Row( | |
| mainAxisAlignment: MainAxisAlignment.center, | |
| children: [ | |
| buildTimeColumn(hours, "Hrs"), | |
| buildTimeColumn(minutes, "Mins"), | |
| buildTimeColumn(seconds, "Secs", isLast: true), | |
| ], | |
| ); | |
| } | |
| Widget buildTimeColumn(String time, String label, {bool isLast = false}) { | |
| return Column( | |
| mainAxisAlignment: MainAxisAlignment.center, | |
| children: [ | |
| Row( | |
| children: [ | |
| buildDigit(time[0]), | |
| buildDigit(time[1]), | |
| if (!isLast) buildTimeSeparator(), | |
| ], | |
| ), | |
| buildLabel(label), | |
| ], | |
| ); | |
| } | |
| Widget buildDigit(String digit) { | |
| return Container( | |
| padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 4), | |
| margin: const EdgeInsets.symmetric(horizontal: 2), | |
| decoration: BoxDecoration( | |
| color: Colors.white, | |
| borderRadius: BorderRadius.circular(8), | |
| ), | |
| child: ClipRect( | |
| child: AnimatedSwitcher( | |
| duration: const Duration(milliseconds: 600), | |
| switchInCurve: Curves.easeOutExpo, | |
| switchOutCurve: Curves.easeInExpo, | |
| transitionBuilder: (Widget child, Animation<double> animation) { | |
| return Stack( | |
| children: <Widget>[ | |
| SlideTransition( | |
| position: Tween<Offset>( | |
| begin: const Offset(0, -1), | |
| end: const Offset(0, 1), | |
| ).animate(CurvedAnimation( | |
| parent: animation, | |
| curve: Curves.easeOutCubic, | |
| )), | |
| child: FadeTransition( | |
| opacity: animation, | |
| child: child, | |
| ), | |
| ), | |
| SlideTransition( | |
| position: Tween<Offset>( | |
| begin: const Offset(0, -1), | |
| end: const Offset(0, 0), | |
| ).animate(CurvedAnimation( | |
| parent: animation, | |
| curve: Curves.bounceIn, | |
| )), | |
| child: FadeTransition( | |
| opacity: animation, | |
| child: child, | |
| ), | |
| ), | |
| ], | |
| ); | |
| }, | |
| child: Text( | |
| digit, | |
| key: ValueKey<String>(digit), | |
| style: const TextStyle( | |
| fontWeight: FontWeight.bold, | |
| color: Colors.black, | |
| fontSize: 50, | |
| ), | |
| ), | |
| ), | |
| ), | |
| ); | |
| } | |
| Widget buildLabel(String label) { | |
| return Text( | |
| label, | |
| style: const TextStyle( | |
| color: Colors.white, | |
| fontSize: 20, | |
| fontWeight: FontWeight.bold, | |
| ), | |
| ); | |
| } | |
| Widget buildTimeSeparator() { | |
| return const Padding( | |
| padding: EdgeInsets.symmetric(horizontal: 2.0), | |
| child: Text( | |
| ":", | |
| style: TextStyle( | |
| color: Colors.white, | |
| fontSize: 50, | |
| ), | |
| ), | |
| ); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
⏳ Discover the Animated Countdown Timer! 🚀
Check out this beautifully animated Countdown Timer built with Flutter! In this guide, we’ll learn how to create a countdown timer that adds smooth transitions, making time tracking not only functional but visually appealing. 🕰️
Ideal for any app that requires a countdown, whether it’s for events, challenges, or even reminders. With this easy-to-follow tutorial, we’ll have a stunning countdown ready to go in no time! 🔥
👉 Read the full guide on Medium
Transform the user experience with this engaging countdown feature today! 🎉
✅ For Count-Up Timer: Check out the complete animated count-up timer code and see how easy it is to integrate this feature into your app.
👉 Explore the GitHub Gist for Animated Count-Up Timer
Visual Preview
animated_count_down_timer_preview.mov