为什么我的按钮 运行 同时有 onTap 功能和 onLongPressDown 功能?

Why does my button run both the onTap function and the onLongPressDown function at the same time?

我正在使用手势检测器来做两件不同的事情:

  1. onTap:录制固定的 10 秒音频
  2. 长按:录制音频直到用户松开按钮,最多 10 秒

长按按钮工作正常,但是当我进行常规点击时,我的 Logcat 说它是 运行 常规点击录音和长按录音。为什么不能区分这两种水龙头?

GestureDetector(
    onTap: () {
      startTapRecording();
      setState(() {
        sendableMyAppExists = 1;
      });
    },
    onLongPressDown: (details) { 
      startLongPressRecording();
    },
    onLongPressUp: () {
      stopLongPressRecording();
      setState(() {
        sendableMyAppExists = 1;
      });
      startPlaying();
    },
),

void startTapRecording() {
    print('##MyApp## startTapRecording: 1');
    controller?.stop();
    controller?.reset();
    cancelTimer();
    print('##MyApp## startTapRecording: 2');
    stopPlaying();
    stopRecording();

    final String filename = getNewMyAppAudioFileID();

    setState(() {
      currentMyAppFilename = filename;
    });

    startRecordingTimer();

    print('##MyApp## startTapRecording: 3');

    startRecording(MyAppsInProgressFileDir.path + currentMyAppFilename);

    controller?.forward();

    print('##MyApp## startTapRecording: 4 (finished)');
}

void startLongPressRecording() async {
    print('##MyApp## startLongPressRecording: 1');
    controller?.stop();
    controller?.reset();
    cancelTimer();
    stopPlaying();
    stopRecording();
    stopwatch.reset();
    stopwatch.start();

    final String filename = getNewMyAppAudioFileID();

    print('##MyApp## startLongPressRecording: 2');

    setState(() {
      currentMyAppFilename = filename;
    });

    startRecordingTimer();

    print('##MyApp## startLongPressRecording: 3');

    startRecording(MyAppsInProgressFileDir.path + currentMyAppFilename);

    controller?.forward();

    print('##MyApp## startLongPressRecording: 4 (finished)');
}

void stopLongPressRecording() {
    cancelTimer();
    stopwatch.stop();

    stopRecording();

    controller?.stop();
    controller?.reset();

    setState(() {
      sendableMyAppExists = 1;
    });
}

Logcat 进行一次常规点击并等待整个 10 秒结束后:

##MyApp## startLongPressRecording: 1
##MyApp## startLongPressRecording: 2
##MyApp## startLongPressRecording: 3
##MyApp## startRecording: 1
##MyApp## cleanupTempAudioFiles: 1
##MyApp## startLongPressRecording: 4 (finished)
##MyApp## startTapRecording: 1
##MyApp## startTapRecording: 2
##MyApp## startTapRecording: 3
##MyApp## startRecording: 1
##MyApp## cleanupTempAudioFiles: 1
##MyApp## startTapRecording: 4 (finished)
##MyApp## cleanupTempAudioFiles: 2 
##MyApp## cleanupTempAudioFiles: 3 (finished)
##MyApp## startRecording: 2
##MyApp## cleanupTempAudioFiles: 2 
##MyApp## cleanupTempAudioFiles: 3 (finished)
##MyApp## startRecording: 2
##MyApp## startRecording: 3 (finished)
##MyApp## handleTimeout sendableMyAppExists: 1
##MyApp## runFFMPEGHighLow
##MyApp## initialize: 1
##MyApp## cleanupTempAudioFiles: 1
##MyApp## cleanupTempAudioFiles: 2 
##MyApp## cleanupTempAudioFiles: file.path = /data/user/0/com.example.MyApp_3/code_cache/MyApp/MyAppAudioFiles/MyAppsInProgress/MyAppAudioFile1
##MyApp## cleanupTempAudioFiles: file.path = /data/user/0/com.example.MyApp_3/code_cache/MyApp/MyAppAudioFiles/MyAppsInProgress/MyAppAudioFile1High.mp3
##MyApp## cleanupTempAudioFiles: 3 (finished)
##MyApp## initialize: 2 (finished)

来自 onLongPressDown

的文档

which might be the start of a long-press.

它说,如果小部件认为发生了长按,包括点击小部件,它就会调用。

在同一文档中,如果您能看到下面一行

If the user completes the long-press, and this gesture wins, onLongPressStart will be called after this callback. Otherwise, onLongPressCancel will be called after this callback.

它说,如果你想在长按开始时跟踪,你可以使用onLongPressStart而不是onLongPressDown

注意:另请查看 onLongPressStart 文档

下面是一段代码,您可以将其粘贴到 dartpad(select flutter 项目)中,并尝试检查其工作原理的控制台

点击时的结果:

on long pressed down
on long press cancel
on tapped

长按结果:

on long pressed down
on long press start
on long pressed up

代码:

import 'package:flutter/material.dart';

const Color darkBlue = Color.fromARGB(255, 18, 32, 47);

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark().copyWith(
        scaffoldBackgroundColor: darkBlue,
      ),
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: MyWidget(),
        ),
      ),
    );
  }
}

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () => print('on tapped'),
      onLongPressUp: () => print('on long pressed up'),
      onLongPressDown: (_) => print('on long pressed down'),
      onLongPressStart: (_) => print('on long press start'),
      onLongPressCancel: () => print('on long press cancel'),
      child: Text(
        'Tap Me',
        style: Theme.of(context).textTheme.headline4,
      ),
    );
  }
}