Таймер обратного отсчета флаттера
Как я могу сделать, чтобы поместить значение, переданное в конструкции, сделать таймер, который округляется до первого знака после запятой и показывает в дочернем тексте моего RaisedButton? Я пытался, но без удачи. Мне удается заставить работать функцию обратного вызова с простым таймером, но без периодического и без обновления значения в реальном времени в тексте...
import 'package:flutter/material.dart';
import 'dart:ui';
import 'dart:async';
class TimerButton extends StatefulWidget {
final Duration timerTastoPremuto;
TimerButton(this.timerTastoPremuto);
@override
_TimerButtonState createState() => _TimerButtonState();
}
class _TimerButtonState extends State<TimerButton> {
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(5.0),
height: 135.0,
width: 135.0,
child: new RaisedButton(
elevation: 100.0,
color: Colors.white.withOpacity(.8),
highlightElevation: 0.0,
onPressed: () {
int _start = widget.timerTastoPremuto.inMilliseconds;
const oneDecimal = const Duration(milliseconds: 100);
Timer _timer = new Timer.periodic(
oneDecimal,
(Timer timer) =>
setState(() {
if (_start < 100) {
_timer.cancel();
} else {
_start = _start - 100;
}
}));
},
splashColor: Colors.red,
highlightColor: Colors.red,
//shape: RoundedRectangleBorder e tutto il resto uguale
shape: BeveledRectangleBorder(
side: BorderSide(color: Colors.black, width: 2.5),
borderRadius: new BorderRadius.circular(15.0)),
child: new Text(
"$_start",
style: new TextStyle(fontFamily: "Minim", fontSize: 50.0),
),
),
);
}
}
Ответы
Ответ 1
Вот пример использования Timer.periodic :
Обратный отсчет начинается с 10
до 0
при нажатии кнопки:
import 'dart:async';
[...]
Timer _timer;
int _start = 10;
void startTimer() {
const oneSec = const Duration(seconds: 1);
_timer = new Timer.periodic(
oneSec,
(Timer timer) => setState(
() {
if (_start < 1) {
timer.cancel();
} else {
_start = _start - 1;
}
},
),
);
}
@override
void dispose() {
_timer.cancel();
super.dispose();
}
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(title: Text("Timer test")),
body: Column(
children: <Widget>[
RaisedButton(
onPressed: () {
startTimer();
},
child: Text("start"),
),
Text("$_start")
],
),
);
}
Результат:
Вы также можете использовать класс CountdownTimer из библиотеки quiver.async, использование еще проще:
import 'package:quiver/async.dart';
[...]
int _start = 10;
int _current = 10;
void startTimer() {
CountdownTimer countDownTimer = new CountdownTimer(
new Duration(seconds: _start),
new Duration(seconds: 1),
);
var sub = countDownTimer.listen(null);
sub.onData((duration) {
setState(() { _current = _start - duration.elapsed.inSeconds; });
});
sub.onDone(() {
print("Done");
sub.cancel();
});
}
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(title: Text("Timer test")),
body: Column(
children: <Widget>[
RaisedButton(
onPressed: () {
startTimer();
},
child: Text("start"),
),
Text("$_current")
],
),
);
}
Ответ 2
Я создал универсальный виджет таймера, который можно использовать для отображения любого таймера, а также его гибкости.
Этот виджет принимает следующие свойства
- secondsRemaining: продолжительность, в течение которой таймер должен работать в секундах
- whenTimeExpires: какое действие необходимо выполнить, если таймер закончил
- countDownStyle: любой стиль, который вы хотите придать таймеру
- countDownFormatter: способ, которым пользователь хочет отобразить таймер обратного отсчета, например
hh mm ss
строка типа 01 hours: 20 minutes: 45 seconds
вы можете предоставить форматтер по умолчанию (formatHHMMSS
) на тот случай, если вы не захотите использовать его везде.
//обеспечить реализацию для этого - formatHHMMSS(duration.inSeconds);
или использовать ниже той, которую я предоставил.
import 'package:flutter/material.dart';
class CountDownTimer extends StatefulWidget {
const CountDownTimer({
Key key,
int secondsRemaining,
this.countDownTimerStyle,
this.whenTimeExpires,
this.countDownFormatter,
}) : secondsRemaining = secondsRemaining,
super(key: key);
final int secondsRemaining;
final Function whenTimeExpires;
final Function countDownFormatter;
final TextStyle countDownTimerStyle;
State createState() => new _CountDownTimerState();
}
class _CountDownTimerState extends State<CountDownTimer>
with TickerProviderStateMixin {
AnimationController _controller;
Duration duration;
String get timerDisplayString {
Duration duration = _controller.duration * _controller.value;
return widget.countDownFormatter != null
? widget.countDownFormatter(duration.inSeconds)
: formatHHMMSS(duration.inSeconds);
// In case user does not provide formatter use the default one
// for that create a method which will be called formatHHMMSS or whatever you like
}
@override
void initState() {
super.initState();
duration = new Duration(seconds: widget.secondsRemaining);
_controller = new AnimationController(
vsync: this,
duration: duration,
);
_controller.reverse(from: widget.secondsRemaining.toDouble());
_controller.addStatusListener((status) {
if (status == AnimationStatus.completed || status == AnimationStatus.dismissed) {
widget.whenTimeExpires();
}
});
}
@override
void didUpdateWidget(CountDownTimer oldWidget) {
if (widget.secondsRemaining != oldWidget.secondsRemaining) {
setState(() {
duration = new Duration(seconds: widget.secondsRemaining);
_controller.dispose();
_controller = new AnimationController(
vsync: this,
duration: duration,
);
_controller.reverse(from: widget.secondsRemaining.toDouble());
_controller.addStatusListener((status) {
if (status == AnimationStatus.completed) {
widget.whenTimeExpires();
} else if (status == AnimationStatus.dismissed) {
print("Animation Complete");
}
});
});
}
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return new Center(
child: AnimatedBuilder(
animation: _controller,
builder: (_, Widget child) {
return Text(
timerDisplayString,
style: widget.countDownTimerStyle,
);
}));
}
}
Использование:
Container(
width: 60.0,
padding: EdgeInsets.only(top: 3.0, right: 4.0),
child: CountDownTimer(
secondsRemaining: 30,
whenTimeExpires: () {
setState(() {
hasTimerStopped = true;
});
},
countDownStyle: TextStyle(
color: Color(0XFFf5a623),
fontSize: 17.0,
height: 1.2),
),
)
пример для форматаHHMMSS:
String formatHHMMSS(int seconds) {
int hours = (seconds / 3600).truncate();
seconds = (seconds % 3600).truncate();
int minutes = (seconds / 60).truncate();
String hoursStr = (hours).toString().padLeft(2, '0');
String minutesStr = (minutes).toString().padLeft(2, '0');
String secondsStr = (seconds % 60).toString().padLeft(2, '0');
if (hours == 0) {
return "$minutesStr:$secondsStr";
}
return "$hoursStr:$minutesStr:$secondsStr";
}