我已经构建了一个工作倒计时时钟,它以小时:分钟:秒的格式显示剩余时间.在有状态窗口小部件中.它使用全屏墨水池来启动和停止它. 我想要做的是将此代码传输到更改通知程序.(我已经安装了一个名为Countdown Timers的更改通知程序),这样我就可以在应用程序的多个页面上看到这个倒计时.

以下是有状态小部件中工作倒计时时钟的代码:

class ChessClock2 extends StatefulWidget {
  const ChessClock2({Key? key}) : super(key: key);

  @override
  State<ChessClock2> createState() => _ChessClock2State();
}

class _ChessClock2State extends State<ChessClock2> {
  static const countdownDuration = Duration(hours: 5, minutes: 10, seconds: 10);
  Duration duration = Duration();
  Timer? timer;

  bool beenPressed = false;

  @override
  void initState() {
    super.initState();
    Reset();
  }

  void Reset() {
    setState(() => duration = countdownDuration);
  }

  void AddTime() {
    final minusSeconds = -1;
    setState(() {
      final seconds = duration.inSeconds + minusSeconds;
      if (seconds < 0) {
        timer?.cancel();
      } else {
        duration = Duration(seconds: seconds);
      }
    });
  }

  void StartTimer() {
    timer = Timer.periodic(
      Duration(seconds: 1),
      (_) => AddTime(),
    );
  }

  void StopTimer() {
    setState(() => timer?.cancel());
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: InkWell(
          onTap: () {
            setState(() {
              beenPressed = !beenPressed;
            });
            beenPressed ? StartTimer() : StopTimer();
          },
          child: Container(
            width: double.infinity,
            height: double.infinity,
            decoration: BoxDecoration(
              color: beenPressed ? kOrange : kBlueGrey900,
              borderRadius: BorderRadius.circular(30),
            ),
            child: Center(
              child: TimeDisplay(),
            ),
          ),
        ),
      ),
    );
  }

  Widget TimeDisplay() {
    String twoDigits(int n) => n.toString().padLeft(2, '0');
    final hours = twoDigits(
      duration.inHours.remainder(60),
    );
    final minutes = twoDigits(
      duration.inMinutes.remainder(60),
    );
    final seconds = twoDigits(
      duration.inSeconds.remainder(60),
    );
    return Text(
      '$hours:$minutes:$seconds',
      style: TextStyle(fontSize: 50),
    );
  }
}

当我传输代码时,我遇到了麻烦,因为我不能在更改通知程序中使用setState,而且我不确定如何转换代码以使其工作. 到目前为止,通过移动各个变量以及小部件TimDisplay,我能够让计时器从更改通知器中正确显示,但不确定如何从更改通知器中使其工作. 这就是我现在的处境:

type hereclass ChessClock3 extends StatefulWidget {
  const ChessClock3({Key? key}) : super(key: key);

  @override
  State<ChessClock3> createState() => _ChessClock3State();
}

class _ChessClock3State extends State<ChessClock3> {
  @override
  void initState() {
    super.initState();
    Reset();
  }

  void Reset() {
    setState(() => duration = countdownDuration);
  }

  void AddTime() {
    final minusSeconds = -1;

    setState(() {
      final seconds = duration.inSeconds + minusSeconds;
      if (seconds < 0) {
        timer?.cancel();
      } else {
        duration = Duration(seconds: seconds);
      }
    });
  }

  void StartTimer() {
    timer = Timer.periodic(
      Duration(seconds: 1),
      (_) => AddTime(),
    );
  }

  void StopTimer() {
    setState(() => timer?.cancel());
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: InkWell(
          onTap: () {
            setState(() {
              context.read<CountdownTimers>().BeenPressed();
            });
            context.read<CountdownTimers>().beenPressed
                ? StartTimer()
                : StopTimer();
          },
          child: Container(
            width: double.infinity,
            height: double.infinity,
            decoration: BoxDecoration(
              color: context.watch<CountdownTimers>().beenPressed
                  ? kKillTeamOrange
                  : kBlueGrey900,
              borderRadius: BorderRadius.circular(30),
            ),
            child: Center(
              child: context.read<CountdownTimers>().TimeDisplay(),
            ),
          ),
        ),
      ),
    );
  }
}

class CountdownTimers with ChangeNotifier {
  Duration _countdownDuration = Duration(hours: 5, minutes: 10, seconds: 10);
  Duration _duration = Duration();
  Timer? timer;
  bool _beenPressed = false;

  Duration get countdownDuration => _countdownDuration;
  Duration get duration => _duration;
  bool get beenPressed => _beenPressed;

  void BeenPressed() {
    _beenPressed = !_beenPressed;
  }

  Widget TimeDisplay() {
    String twoDigits(int n) => n.toString().padLeft(2, '0');
    final hours = twoDigits(
      _duration.inHours.remainder(60),
    );
    final minutes = twoDigits(
      _duration.inMinutes.remainder(60),
    );
    final seconds = twoDigits(
      _duration.inSeconds.remainder(60),
    );
    return Text(
      '$hours:$minutes:$seconds',
      style: TextStyle(fontSize: 50),
    );
  }
}

如果有人能告诉我如何翻译代码,将不胜感激. 非常感谢!

推荐答案

我会使用Flutter 翼Riverpod,就像下面的代码一样.在Riverpod中,不推荐使用更改通告程序.即使在复杂应用中也是如此.若要更改更改通告程序的状态,必须调用NotifyListeners.

import 'dart:async';

import 'package:flutter_riverpod/flutter_riverpod.dart';

final countDownControllerProvider = StateNotifierProvider.family
    .autoDispose<CountdownController, Duration, Duration>((ref, initialDuration) {
  return CountdownController(initialDuration);
});

class CountdownController extends StateNotifier<Duration> {
  Timer? timer;
  final Duration initialDuration;

  CountdownController(this.initialDuration) : super(initialDuration) {
    startTimer();
  }

  void startTimer() {
    timer = Timer.periodic(const Duration(seconds: 1), (timer) {
      if (state == Duration.zero) {
        timer.cancel();
      } else {
        if (mounted) {
          state = state - const Duration(seconds: 1);
        } else {
          timer.cancel();
        }
      }
    });
  }

  void stopTimer() {
    timer?.cancel();
  }

  void resetTimer({required Duration initialDuration}) {
    stopTimer();
    state = initialDuration;
    startTimer();
  }

  void addTime({required Duration duration}) {
    state = state + duration;
  }

  void subtractTime({required Duration duration}) {
    state = state - duration;
  }

  @override
  void dispose() {
    timer?.cancel();
    super.dispose();
  }
}

然后在小部件中

Consumer(builder: (context, ref, _) {
                          return Text(
                            ref
                                .watch(countDownControllerProvider(
                                    const Duration(
                                        days: 25,
                                        hours: 15,
                                        minutes: 36,
                                        seconds: 45)))
                                .formatDuration(),
                            style: context.theme.textTheme.bodyText1!
                                .copyWith(color: Colors.white),
                          );
                        })

最后,毫不犹豫地将您的转换逻辑持续时间转换为字符串,放入一个扩展

extension DurationExtensions on Duration {
  String formatDuration() {
    int seconds = inSeconds;
    final days = seconds~/Duration.secondsPerDay;
    seconds -= days*Duration.secondsPerDay;
    final hours = seconds~/Duration.secondsPerHour;
    seconds -= hours*Duration.secondsPerHour;
    final minutes = seconds~/Duration.secondsPerMinute;
    seconds -= minutes*Duration.secondsPerMinute;

    final List<String> tokens = [];
    if (days != 0) {
      tokens.add('${days}d');
    }
    if (tokens.isNotEmpty || hours != 0){
      tokens.add('${hours}h');
    }
    if (tokens.isNotEmpty || minutes != 0) {
      tokens.add('${minutes}min');
    }
    if(tokens.isNotEmpty || seconds != 0) {
      tokens.add('${seconds}s');
    }

    return tokens.join('');
  }
}

Flutter相关问答推荐

为什么我不能看到类音频源在flutter?'

来自FutureProvider的数据只打印两个不同的变量,它们对一个实例只有一次相同的值,为什么?

为什么我的PIN字段在第一次打字时不显示数字?

如何在Ffltter Chrome应用程序中使用webview_fltter_web显示自定义html而不是外部uri?

如何让两个展开的Widget根据其子窗口的屏幕大小

为什么我的图标的一半在定位小部件中消失了?

Flutter Riverpod 没有捕获 List 的嵌套值变化

在 Flutter 中解码 BLE 设备负载

如果有空间则居中CustomScrollView

如何从列表中更新provider变量:Flutter列表和Provider优化指南

如何停止折线图的抖动

如何删除或隐藏覆盖

底部工作表顶部的一块 Flutter

Flutter Serverpod 在示例项目上返回 400 错误

为什么 setState 不改变我的变量 Flutter?

出现错误;运算符[]不是为对象类型定义的?功能()'

Firebase Cloud Messaging (Flutter):订阅主题时出现错误消息

在 Flutter 中,如何使用文本字段和方形图像进行行布局

如何使用我拥有的 .jks 文件签署我的应用程序

如何在 CircleAvatar 中使用 Stack