Home > front end >  Why does my button run both the onTap function and the onLongPressDown function at the same time?
Why does my button run both the onTap function and the onLongPressDown function at the same time?

Time:05-20

I'm using a gesture detector to do 2 different things:

  1. onTap: record audio for a fixed 10 seconds
  2. on long press: record audio until the user releases the button, up to a maximum of 10 seconds

Long pressing the button is working fine, but when I do a regular tap my Logcat says that it's running both the regular tap recording and the long press recording. Why can't it differentiate between the two types of taps?

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 after doing a single regular tap and waiting until the whole 10 seconds is up:

##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)

CodePudding user response:

From the docs of onLongPressDown

which might be the start of a long-press.

It says that the widget calls if it thinks the long press happens which includes tapping the widget.

In the same documentation, if you can see the below line

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.

It says, if you want to track when long press is started, you can use onLongPressStart instead of onLongPressDown.

Note: also check onLongPressStart docs

Below is a code which you can paste in dartpad (select flutter project) and try to check the console of how it works

Result when tapped:

on long pressed down
on long press cancel
on tapped

Result when long pressed:

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

Code:

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,
      ),
    );
  }
}
  • Related