'Flutter detect triple tap

I would like to be able to detect a triple tap (or even more) in a Flutter widget, although GestureDetector only has detection for double-tap built in.

What is the easiest way for me to detect a triple tap on a widget?

(I want continually clicking on a part of the screen to unlock some developer options)



Solution 1:[1]

Was a bit lazy with this one, in reality it's not that hard

// init
int lastTap = DateTime.now().millisecondsSinceEpoch;
int consecutiveTaps = 0;

GestureDetector(
        onTap: () {
          int now = DateTime.now().millisecondsSinceEpoch;
          if (now - lastTap < 1000) {
            print("Consecutive tap");
            consecutiveTaps ++;
            print("taps = " + consecutiveTaps.toString());
            if (consecutiveTaps > 4){
              // Do something
            }
          } else {
            consecutiveTaps = 0;
          }
          lastTap = now;
        },
        child: ...
)

Solution 2:[2]

I have tried this method with reduced timeout and with both double and triple tap

int lastTap = DateTime.now().millisecondsSinceEpoch;
int consecutiveTaps = 1;
GestureDetector(
      onTap: () {
        int now = DateTime.now().millisecondsSinceEpoch;
        if (consecutiveTaps == 1) {
          print("taps = " + consecutiveTaps.toString());
          lastTap = now;
        }
        if (now - lastTap < 300) {
          print("Consecutive tap");
          consecutiveTaps++;
          print("taps = " + consecutiveTaps.toString());
          if (consecutiveTaps == 3) {
            print("Consecutive tap 3");
          } else if (consecutiveTaps == 2) {
             print("Consecutive tap 2");
          }
        } else {
          consecutiveTaps = 1;
        }
        lastTap = now;
      },
      child: \\child);

Solution 3:[3]

I took a little different approach. Instead of having to compare timestamps, I set a Timer, which will reset the tapped state. But each time there is a tap, the old timer is canceled.

Timer? devPageClickTimer;
num devPageTapped = 0;
final devPageTapGoal = 5;

GestureDetector(
  onTap: () {
    devPageTapped++;
    if (devPageTapped >= devPageTapGoal) {
      router.push(const DeveloperRoute());
    }

    if (devPageClickTimer != null) {
      devPageClickTimer!.cancel();
    }

    devPageClickTimer = Timer(const Duration(milliseconds: 200), () => devPageTapped = 0);
},

Solution 4:[4]

I tried the method mentioned here, but it didn't work for me. GestureDetector onTap is called only once, regardless of the number of taps. Probably something has changed in flutter (I'm on the beta channel). However, I dug into the source code of flutter and come to the solution (https://api.flutter.dev/flutter/gestures/SerialTapGestureRecognizer-class.html):

import "package:flutter/gestures.dart";

RawGestureDetector(gestures: {
      SerialTapGestureRecognizer:
        GestureRecognizerFactoryWithHandlers<SerialTapGestureRecognizer>(
          () =>SerialTapGestureRecognizer(), (SerialTapGestureRecognizer instance) {
        instance.onSerialTapDown = (SerialTapDownDetails details) {
          if (details.count == 3) print("Consecutive tap 3");
        };
      })

Solution 5:[5]

I like this simple approach, without so many nested if blocks.

// Variables in the state class
var startTap = timeNow;
var consecutiveTaps = 0;
static const int serialTaps = 4;
static const int tapDurationInMs = 1000;
static int get timeNow => DateTime.now().millisecondsSinceEpoch;

// Build method
GestureDetector(
  onTap: () {
    final now = timeNow;
    final userExceededTapDuration = now - startTap > tapDurationInMs;

    if (userExceededTapDuration) {
      consecutiveTaps = 0;
      startTap = now;
    }

    consecutiveTaps++;

    if (consecutiveTaps == serialTaps) {
      // widget.onTap();
    }
  },
);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 BGH
Solution 2 Nimitt Sethiya
Solution 3 Volker Andres
Solution 4 kernel
Solution 5 Stefan Rein