Flutter检测三次点击

9

我希望能在Flutter小部件中检测三次轻拍(甚至更多),但是GestureDetector只内置了双击检测。

在小部件上检测三次轻拍的最简单方法是什么?

(我想要不停地点击屏幕上的某个部分以解锁一些开发人员选项)

6个回答

12

这个有点懒,实际上并不那么难

// 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: ...
)

你可能想使用300毫秒,这是Flutter框架用于双击超时的时间:https://api.flutter.dev/flutter/gestures/kDoubleTapTimeout-constant.html - dumazy

6

我尝试了这里提到的方法,但对我没有用。无论点击次数如何,GestureDetector onTap只被调用一次。可能在flutter中有些变化(我在beta频道上)。 然而,我深入研究了flutter的源代码并找到了解决方案(https://api.flutter.dev/flutter/gestures/SerialTapGestureRecognizer-class.html):

import "package:flutter/gestures.dart";
import 'package:flutter/material.dart';

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

  //  child: // your widget,
);


2

相关解决方案。 这是基于Listener widget的灵活可重复使用的多点触控小部件,它报告原始指针事件:

class AppMultipleTap extends StatefulWidget {
  final Widget child;
  final VoidCallback onMultipleTap;
  final int taps;
  final Duration duration;

  const AppMultipleTap({
    super.key,
    required this.child,
    required this.onMultipleTap,
/// feel free to override these values
    this.taps = 3,
    this.duration = const Duration(milliseconds: 600),
  });

  @override
  State<AppMultipleTap> createState() => _AppMultipleTapState();
}

class _AppMultipleTapState extends State<AppMultipleTap> {
/// in _count we store current number of taps
  int _count = 0;
  Timer? _timer;

  @override
  Widget build(BuildContext context) {
    return Listener(
      onPointerDown: (_) {
        if (_timer == null) _startTimer();
        _count++;
      },
      child: widget.child,
    );
  }

  void _startTimer() {
    _timer = Timer(widget.duration, () {
/// you can change this condition to ==, if you need 100% match
      if (_count >= widget.taps) {
        widget.onMultipleTap.call();
      }
      _timer = null;
      _count = 0;
    });
  }
}

然后您可以像这样使用它:
 @override
  Widget build(BuildContext context) {
    return AppMultipleTap(
      onMultipleTap: /// Do some action

2
我已尝试过减少超时时间以及使用双击和三击的方法。
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);

2
我采取了一种略有不同的方法。我设置了一个计时器来重置被点击状态,而不是需要比较时间戳。但每次有一个新的点击事件发生时,旧的计时器就会被取消。
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);
},

0

我喜欢这种简单的方法,没有那么多嵌套的if块。

// 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();
    }
  },
);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接