skip to Main Content

I am trying to implement the button, where on long press you need to hold a breath for 10 seconds, and for user I want to show how many seconds left, but with the current implementation number is static on long press and I cannot get why, because function is called inside onLongPress and cancelled onLongPressEnd.

      late Timer ?timer;
      int _counter = 10;
      void startTimer() {
      const oneSec = const Duration(seconds: 10);
      timer = new Timer.periodic(
      oneSec,
      (Timer ?timer) {
      if (_counter == 0) {
      setState(() {
         timer?.cancel();
      });
      } else {
        setState(() {
        _counter--;
        });
      }
      },
      );

      OnLongPress implementation
      onLongPress: () {
      startTimer(); 
      setState(() {
        _counter;}
      onLongPressEnd: (details) {
          timer?.cancel();
      setState(() {
      _isLongPressActivated = false;
      }, 

Thanks a lot for any help on that

2

Answers


  1. There may be more than one issue with the code you posted, but I took your code and here’s a working ticker based on the getting-started app:

    import 'dart:async';
    
    import 'package:flutter/material.dart';
    
    void main() => runApp(const MyApp());
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
      static const String _title = 'Flutter Stateful Clicker Counter';
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: _title,
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: const MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      const MyHomePage({super.key});
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      ValueNotifier<int> _counter = ValueNotifier(10);
    
      late Timer? timer;
    
      final oneSec = const Duration(seconds: 1);
    
      void tickCounter() {
        print("ticking counter ${_counter.value}");
        if (_counter.value <= 0) {
          cancelTimer();
          return;
        }
        _counter.value = _counter.value - 1;
      }
    
      void startTimer() {
        timer = Timer.periodic(
          oneSec,
          (Timer? timer) {
            tickCounter();
          },
        );
      }
    
      void cancelTimer() {
        timer?.cancel();
      }
    
      void onLongPressStarted() {
        print("Long press started");
        startTimer();
      }
    
      void onLongPressCanceled() {
        print("Long press ended");
        cancelTimer();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text('Flutter Demo Click Counter'),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                GestureDetector(
                    onLongPress: onLongPressStarted,
                    onLongPressCancel: onLongPressCanceled,
                    child: Container(
                      child: Text("Hold Me"),
                    )),
                ValueListenableBuilder(
                    valueListenable: _counter,
                    builder: (context, value, child) => Text(
                          value.toString(),
                          style: const TextStyle(fontSize: 25),
                        )),
              ],
            ),
          ),
        );
      }
    }
    
    
    Login or Signup to reply.
  2. GestureDetecture with onTapDown and onTapUp are the right callbacks you need to implement.

    class MyHomePage extends StatefulWidget {
      const MyHomePage({super.key});
     
      @override
      State<MyHomePage> createState() => _MyHomePageState();
    }
     
    class _MyHomePageState extends State<MyHomePage> {
      int _counter = 10;
     
      Timer? _timer;
     
      @override
      void dispose() {
        _timer?.cancel();
        super.dispose();
      }
     
      void _startTimer() {
        _timer?.cancel();
        _timer = Timer.periodic(
          const Duration(seconds: 1),
          (Timer? timer) {
            if (_counter <= 0) {
              return;
            }
            setState(() {
              _counter--;
            });
          },
        );
      }
     
      void _resetTimer() {
        _timer?.cancel();
        setState(() {
          _counter = 10;
        });
      }
     
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            backgroundColor: Theme.of(context).colorScheme.inversePrimary,
            title: Text(widget.title),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                GestureDetector(
                  onTapDown: (_) => _startTimer(),
                  onTapUp: (_) => _resetTimer(),
                  child: const ColoredBox(
                    color: Colors.cyan,
                    child: Text(
                      'Press and hold',
                    ),
                  ),
                ),
                Text(
                  '$_counter',
                  style: Theme.of(context).textTheme.headlineMedium,
                ),
              ],
            ),
          ),
        );
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search