我使用RestartableTimer
(Timer
的子类)作为倒数计时器,以便在一定时间后将用户“踢出”表单。
我想显示该计时器的进度,并且我希望逐渐填充循环进度的想法。
我没有显示我的代码,因为我实际上没有什么可显示的。我在小部件(有状态或无状态,以效果最佳的一个)中有一个完全静态的进度指示器和一个工作计时器。
我面临两个问题,这是我需要帮助的地方:
我不知道如何每隔x毫秒检查一次计时器进度。我怎样才能做到这一点?我不需要复制粘贴代码,但是我应该选择更多的“对象/方向”?
未完成以计时器为单位的计时器进度(NotImplementedException);有什么办法在其他地方有同等学历吗?该对象对我来说真的很好,除了那部分。
我是SOL还是有办法做到?
答案 0 :(得分:1)
getter tick
中没有实现任何内容,因为RestartableTimer
不是周期性的。您想要的是一件更加复杂的事情,RestartableTimer
无法帮助您。
首先,您需要一些东西来控制CircularProgressIndicator
的进度:
class ProgressController {
static const double smoothnessConstant = 250;
final Duration duration;
final Duration tickPeriod;
Timer _timer;
Timer _periodicTimer;
Stream<void> get progressStream => _progressController.stream;
StreamController<void> _progressController = StreamController<void>.broadcast();
Stream<void> get timeoutStream => _timeoutController.stream;
StreamController<void> _timeoutController = StreamController<void>.broadcast();
double get progress => _progress;
double _progress = 0;
ProgressController({@required this.duration})
: assert(duration != null),
tickPeriod = _calculateTickPeriod(duration);
void start() {
_timer = Timer(duration, () {
_cancelTimers();
_setProgressAndNotify(1);
_timeoutController.add(null);
});
_periodicTimer = Timer.periodic(
tickPeriod,
(Timer timer) {
double progress = _calculateProgress(timer);
_setProgressAndNotify(progress);
},
);
}
void restart() {
_cancelTimers();
start();
}
Future<void> dispose() async {
await _cancelStreams();
_cancelTimers();
}
double _calculateProgress(Timer timer) {
double progress = timer.tick / smoothnessConstant;
if (progress > 1) return 1;
if (progress < 0) return 0;
return progress;
}
void _setProgressAndNotify(double value) {
_progress = value;
_progressController.add(null);
}
Future<void> _cancelStreams() async {
if (!_progressController.isClosed) await _progressController.close();
if (!_timeoutController.isClosed) await _timeoutController.close();
}
void _cancelTimers() {
if (_timer?.isActive == true) _timer.cancel();
if (_periodicTimer?.isActive == true) _periodicTimer.cancel();
}
static Duration _calculateTickPeriod(Duration duration) {
double tickPeriodMs = duration.inMilliseconds / smoothnessConstant;
return Duration(milliseconds: tickPeriodMs.toInt());
}
}
然后,您可以实现一个CircularProgressIndicator
来监听Stream
中的ProgressController
:
class RestartableCircularProgressIndicator extends StatefulWidget {
final ProgressController controller;
final VoidCallback onTimeout;
RestartableCircularProgressIndicator({
Key key,
@required this.controller,
this.onTimeout,
}) : assert(controller != null),
super(key: key);
@override
_RestartableCircularProgressIndicatorState createState() =>
_RestartableCircularProgressIndicatorState();
}
class _RestartableCircularProgressIndicatorState
extends State<RestartableCircularProgressIndicator> {
ProgressController get controller => widget.controller;
VoidCallback get onTimeout => widget.onTimeout;
@override
void initState() {
super.initState();
controller.progressStream.listen((_) => updateState());
controller.timeoutStream.listen((_) => onTimeout());
}
@override
Widget build(BuildContext context) {
return CircularProgressIndicator(
value: controller.progress,
);
}
void updateState() => setState(() {});
}
您还可以将CircularProgressIndicator
的某些参数传递给RestartableCircularProgressIndicator
,以便对其进行自定义。
一个用法示例:
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
ProgressController controller;
@override
void initState() {
super.initState();
controller = ProgressController(
duration: Duration(seconds: 5),
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RestartableCircularProgressIndicator(
controller: controller,
onTimeout: () => print('timeout'),
),
RaisedButton(
onPressed: controller.start,
child: Text('Start'),
),
RaisedButton(
onPressed: controller.restart,
child: Text('Restart'),
),
],
),
),
),
);
}
}
有一天我会将其转换为库,但是在此之前,我无法提供此代码的测试和文档,因此如果您想了解这里发生的情况,则必须进行研究(很抱歉... )。