Kinda Code
Home/Flutter/How to Create a Stopwatch in Flutter

How to Create a Stopwatch in Flutter

Last updated: February 14, 2023

A stopwatch in a mobile app is a tool that measures elapsed time for a specific event or task. It includes start, stop (can be replaced with pause), and reset buttons and displays the time in a numerical format (e.g., minutes, seconds, and milliseconds). It’s commonly used for timing sports, cooking, studying, working, and more.

This practical shows you how to create a stopwatch app with Flutter.

Overview

The Stopwatch class

We take advantage of a built-in class in Flutter named Stopwatch to achieve the goal much more conveniently. This class provides a way to measure elapsed time. It can be started, stopped, and reset, and the elapsed time can be obtained as a Duration object. The Stopwatch class can measure elapsed time in milliseconds or microseconds with platform-dependent accuracy.

Initialize an instance of the Stopwatch class:

final Stopwatch _stopwatch = Stopwatch();

Below are the most useful methods and properties:

  • start(): Starts measuring elapsed time.
  • stop(): Stops measuring elapsed time.
  • reset(): Resets the Stopwatch to an elapsed time of zero.
  • elapsed: Returns the elapsed time as a Duration object.
  • isRunning: Returns a Boolean value indicating whether the Stopwatch is currently running.

Besides the Stopwatch class, we will also make use of the Timer class to periodically update the UI. See this article if you want more details: Working with Timer and Timer.periodic in Flutter.

Complete Example

Preview

The small app below is what we’re going to make:

The Code

Here’s the entire code, along with commentaries explaining what each block does:

// KindaCode.com
// main.dart
import 'dart:async';
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      // Remove the debug banner
      debugShowCheckedModeBanner: false,
      title: 'KindaCode.com',
      home: KindaCodeDemo(),
    );
  }
}

class KindaCodeDemo extends StatefulWidget {
  const KindaCodeDemo({super.key});

  @override
  State<KindaCodeDemo> createState() => _KindaCodeDemoState();
}

class _KindaCodeDemoState extends State<KindaCodeDemo> {
  // Initialize an instance of Stopwatch
  final Stopwatch _stopwatch = Stopwatch();

  // Timer
  late Timer _timer;

  // The result which will be displayed on the screen
  String _result = '00:00:00';

  // This function will be called when the user presses the Start button
  void _start() {
    // Timer.periodic() will call the callback function every 100 milliseconds
    _timer = Timer.periodic(const Duration(milliseconds: 30), (Timer t) {
      // Update the UI
      setState(() {
        // result in hh:mm:ss format
        _result =
            '${_stopwatch.elapsed.inMinutes.toString().padLeft(2, '0')}:${(_stopwatch.elapsed.inSeconds % 60).toString().padLeft(2, '0')}:${(_stopwatch.elapsed.inMilliseconds % 100).toString().padLeft(2, '0')}';
      });
    });
    // Start the stopwatch
    _stopwatch.start();
  }

  // This function will be called when the user presses the Stop button
  void _stop() {
    _timer.cancel();
    _stopwatch.stop();
  }

  // This function will be called when the user presses the Reset button
  void _reset() {
    _stop();
    _stopwatch.reset();

    // Update the UI
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('KindaCode.com'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // Display the result
            Text(
              _result,
              style: const TextStyle(
                fontSize: 50.0,
              ),
            ),
            const SizedBox(
              height: 20.0,
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                // Start button
                ElevatedButton(
                  onPressed: _start,
                  child: const Text('Start'),
                ),
                // Stop button
                ElevatedButton(
                  onPressed: _stop,
                  style: ElevatedButton.styleFrom(
                    backgroundColor: Colors.red,
                  ),
                  child: const Text('Stop'),
                ),
                // Reset button
                ElevatedButton(
                  onPressed: _reset,
                  style: ElevatedButton.styleFrom(
                    backgroundColor: Colors.green,
                  ),
                  child: const Text('Reset'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

Conclusion

Overall, using the Stopwatch class is a convenient way to add timing functionality to a Flutter app. Without this class, most likely, we would have had to write more and more code for the small application above.

Are you tired and sleepy yet? If not, keep learning new things about Flutter through these tutorials:

You can also tour around our Flutter topic page or Dart topic page for the most recent tutorials and examples.