【问题标题】:How to change value of timer on gesture tap?如何更改手势点击计时器的值?
【发布时间】:2021-09-27 17:17:15
【问题描述】:

所以我的计时器遇到了另一个问题。

我有一个大小合适的盒子,当我点击它时,我希望计时器将值从 5 分钟更改为 15 分钟(或者最好,当我第一次点击时,它会从 5 分钟> 10 分钟增加到第二次点击 15 分钟,第三次点击 20 分钟,第四次点击 25 分钟) 为此,计时器不应处于活动状态(用户只能在计时器未运行时更改它) - 但我遇到了“未定义名称'isRunning'”的问题。来自我在另一个小部件中的最终结果

这是我的代码(还有一个问题,目前计时器只显示秒,我怎样才能让它显示实际的 5 分钟,如 5:00)

class timeryypage extends State<timerry> {
  static const maxSeconds = 5;
  int seconds = maxSeconds;
  Timer? timer;

  void resetTimer() => setState(() => seconds = maxSeconds);

  void startTimer({bool reset = true}) {
    if (reset) {
      resetTimer();
    }
    timer = Timer.periodic(Duration(seconds: 1), (_) {
      //add here instead seconds say minutes/miliseconds
      if (!mounted) // Putting this line of code with return under, fixed my issue i been having about mounted
        return;
      else if (seconds > 0) {
        setState(() => seconds--);
      } else {
        stopTimer(reset: false);
      }
    });
  }

  void stopTimer({bool reset = true}) {
    if (reset == mounted) {
      resetTimer();
    }
    setState(() => timer?.cancel());
  }

  @override
  Widget buildButtons() {
    final isRunning = timer == null ? false : timer!.isActive;
    final isCompleted = seconds == maxSeconds || seconds == 0;
    return isRunning || !isCompleted
        ? Row(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              ButtonWidget(
                text: isRunning ? "Pause" : "Resume",
                onClicked: () {
                  if (isRunning) {
                    stopTimer(reset: false);
                  } else {
                    startTimer(reset: false);
                  }
                },
              ),
              const SizedBox(width: 12),
              ButtonWidget(text: "Cancel", onClicked: stopTimer)
            ],
          )
        : ButtonWidget(
            text: "Start Timer!",
            color: Colors.black,
            backgroundColor: Colors.white,
            onClicked: () {
              startTimer();
            },
          );
  }

  Widget buildTimer() => SizedBox(
        width: 200,
        height: 200,
        child: Stack(
          fit: StackFit.expand,
          children: [
            CircularProgressIndicator(
              value: seconds / maxSeconds,
              //if you delete 1 - then it goes to other direction
              valueColor: AlwaysStoppedAnimation(Colors.white),
              strokeWidth: 12,
              backgroundColor: Colors.greenAccent,
            ),
            GestureDetector(
              behavior: HitTestBehavior.opaque,
              onTap: () {
                if (isRunning) {
                  print("do nothing");
                } else {
                  const snackBar = SnackBar(content: Text('Tap'));
                  ScaffoldMessenger.of(context).showSnackBar(snackBar);
                  print("tapped");
                  // later on i want to change timer from 5 minutes 10 minutes on first tap, then second tap to 15 minutes
                }
              },
              child: Center(child: buildTime()),
            ),
            //Center(child: buildTime()),
          ],
        ),
      );

  Widget buildTime() {
    if (seconds == 0) {
      return Icon(Icons.done, color: Colors.greenAccent, size: 112);
    } else {
      return Text(
        "$seconds",
        style: TextStyle(
          fontWeight: FontWeight.bold,
          color: Colors.white,
          fontSize: 80,
        ),
      );
    }
  }

非常感谢您的帮助!

编辑添加额外代码:

bool get isRunning => _timer?.isActive ?? false;
  int _seconds = 00;
  int _minutes = setminutes;
  static const setminutes = 25;
  Timer? _timer;
  var f = NumberFormat("00");

  void _stopTimer({bool reset = true}) {
    if (reset == true) {
      resetTimer();
    }
    setState(() => _timer?.cancel());
    ;
  }

  void resetTimer() => setState(() => _minutes = setminutes);

  void _startTimer({bool reset = true}) {
    if (reset) {
      resetTimer();
    }
    if (_timer != null) {
      _stopTimer();
    }
    if (_minutes > 0) {
      _seconds = _minutes * 60;
    }
    if (_seconds > 60) {
      _minutes = (_seconds / 60).floor();
      _seconds -= (_minutes * 60);
    }
    _timer = Timer.periodic(Duration(seconds: 1), (_) {
      if (!mounted)
        return;
      else if (_seconds > 0) {
        setState(() => _seconds--);
      }

      setState(() {
        if (_seconds > 0) {
          _seconds--;
        } else {
          if (_minutes > 0) {
            _seconds = 59;
            _minutes--;
          } else {
            _stopTimer(reset: false);
          }
        }
      });
    });
  }

  @override
  Widget buildButtons() {
    //final isRunning = timer == null ? false : timer!.isActive;
    final isCompleted = _minutes == setminutes || _seconds == 0;
    return isRunning || !isCompleted
        ? Row(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              ButtonWidget(
                text: isRunning ? "Pause" : "Resume",
                onClicked: () {
                  if (isRunning) {
                    _stopTimer(reset: false);
                  } else {
                    _startTimer(reset: false);
                  }
                },
              ),
              const SizedBox(width: 12),
              ButtonWidget(
                  text: "Cancel",
                  onClicked: () {
                    _stopTimer(reset: true);
                  })
            ],
          )
        : ButtonWidget(
            text: "Start Timer!",
            color: Colors.black,
            backgroundColor: Colors.white,
            onClicked: () {
              _startTimer();
            },
          );
  }

【问题讨论】:

  • isRunningbuildButtons 函数的局部变量。如果你想在那个函数之外引用它,你应该做一个 getter(你可以稍微简化一下):bool get isRunning =&gt; timer?.isActive ?? false;.
  • 非常感谢!有用!。你知道我怎么能做到,而不是在 5 秒内显示“5”,而是显示 5:00(5 分钟)?是否有一些快速修复我的代码或者我必须以某种方式重写大部分代码?
  • 感谢您的帮助!我有错误,因为它告诉我“方法'padLeft'没有为'int'类型定义。”任何想法:?
  • 谢谢!作品。但是,当我将静态 const maxSeconds 例如更改为 120(2 分钟)时,它显示 2:120,我该如何编辑代码,以便当我输入 120 秒时它会显示 2:00 :?我认为我的整个代码都需要重写:|
  • 糟糕,抱歉。我只是写一个答案,以便我可以纠正我的错误。 =)

标签: android flutter dart timer


【解决方案1】:

您的buildTime 函数根据秒数创建一个Text 小部件。如果您想以其他方式对其进行格式化,您需要自己将秒数格式化为String。例如:

var minutes = seconds ~/ 60;
var remainderSeconds = seconds % 60;
return Text('$minutes:${remainderSeconds.toString().padLeft(2, '0')}',
  ...);

另见:

【讨论】:

  • 非常感谢您的帮助,我非常感谢! - 一个问题,因为我在谷歌上找不到答案,当我按下 onClick 时,如何更改我的 maxSeconds 静态常量?例如再增加 300 秒?
  • const 表示无法更改。如果你想改变它,不要使用const
  • 我把它变成了 var,并且“迟到”了 int 秒。我现在遇到的问题是,当我单击按钮添加更多秒数时,它不会自动更新屏幕上的秒数/计时器,但是当我按下启动计时器时,它会从更新的计时器运行,这会增加额外的秒数。当我单击按钮并立即添加显示的额外时间时,我该如何做到这一点?
  • 您是否要增加更多秒数,您是通过致电setState 来增加的吗?如果不这样做,则不会重建小部件树。您还应该针对个别问题提出单独的问题。
  • 我只是把它maxSeconds = 1000; 放在手势点击上 --- 好的,它会变成单独的问题
猜你喜欢
  • 1970-01-01
  • 2013-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-27
  • 1970-01-01
  • 2017-04-25
  • 1970-01-01
相关资源
最近更新 更多