使用 flutter 进度条组件和 RotatedBox 旋转组件,实现时间流失进度条
进度条组件LinearProgressIndicator
属性说明:
value 0-1 之间 进度
RotatedBox 组件
quarterTurns 属性表示象限
quarterTurns: 0 水平
quarterTurns: 1 顺时针旋转 90 度(quarterTurns = 1)
quarterTurns: -1 逆时针旋转 90 度(quarterTurns = -1)。
代码实现
library flutter_timer_countdown; import 'dart:async'; import 'package:LS/common/global.dart'; import 'package:flutter/widgets.dart'; import 'package:get/get.dart'; enum CountDownTimerFormat { daysHoursMinutesSeconds, daysHoursMinutes, daysHours, daysOnly, hoursMinutesSeconds, hoursMinutes, hoursOnly, minutesSeconds, minutesOnly, secondsOnly, } typedef OnTickCallBack = void Function(Duration remainingTime); class TimerCountdown extends StatefulWidget { /// Format for the timer coundtown, choose between different `CountDownTimerFormat`s final CountDownTimerFormat format; /// Defines the time when the timer is over. final DateTime endTime; /// Gives you remaining time after every tick. final OnTickCallBack? onTick; /// Function to call when the timer is over. final VoidCallback? onEnd; /// Toggle time units descriptions. final bool enableDescriptions; /// `TextStyle` for the time numbers. final TextStyle? timeTextStyle; /// `TextStyle` for the colons betwenn the time numbers. final TextStyle? colonsTextStyle; /// `TextStyle` for the description final TextStyle? descriptionTextStyle; /// Days unit description. final String daysDescription; /// Hours unit description. final String hoursDescription; /// Minutes unit description. final String minutesDescription; /// Seconds unit description. final String secondsDescription; /// Defines the width between the colons and the units. final double spacerWidth; final Widget? rightWidget; // 结束的 组件 final Widget? endWidget; const TimerCountdown({ required this.endTime, this.format = CountDownTimerFormat.daysHoursMinutesSeconds, this.enableDescriptions = true, this.onEnd, this.timeTextStyle, this.onTick, this.colonsTextStyle, this.descriptionTextStyle, this.daysDescription = "Days", this.hoursDescription = "Hours", this.minutesDescription = "Minutes", this.secondsDescription = "Seconds", this.spacerWidth = 10, this.rightWidget, this.endWidget, }); @override _TimerCountdownState createState() => _TimerCountdownState(); } class _TimerCountdownState extends State{ bool isEnd = false; Timer? timer; late String countdownDays; late String countdownHours; late String countdownMinutes; late String countdownSeconds; late Duration difference; @override void initState() { _startTimer(); super.initState(); } @override void dispose() { if (timer != null) { timer!.cancel(); } super.dispose(); } /// Calculate the time difference between now end the given [endTime] and initialize all UI timer values. /// /// Then create a periodic `Timer` which updates all fields every second depending on the time difference which is getting smaller. /// When this difference reached `Duration.zero` the `Timer` is stopped and the [onEnd] callback is invoked. void _startTimer() { if (widget.endTime.isBefore(Global.serverTime)) { difference = Duration.zero; } else { difference = widget.endTime.difference(Global.serverTime); } countdownDays = _durationToStringDays(difference); countdownHours = _durationToStringHours(difference); countdownMinutes = _durationToStringMinutes(difference); countdownSeconds = _durationToStringSeconds(difference); if (difference == Duration.zero) { if (widget.onEnd != null) { widget.onEnd!(); } setState(() { isEnd = true; }); } else { timer = Timer.periodic(const Duration(seconds: 1), (timer) { difference = widget.endTime.difference(Global.serverTime); widget.onTick?.call(difference); setState(() { countdownDays = _durationToStringDays(difference); countdownHours = _durationToStringHours(difference); countdownMinutes = _durationToStringMinutes(difference); countdownSeconds = _durationToStringSeconds(difference); }); if (difference <= Duration.zero) { timer.cancel(); if (widget.onEnd != null) { widget.onEnd!(); } setState(() { isEnd = true; }); } }); } } @override Widget build(BuildContext context) { return Wrap( children: [ if (widget.rightWidget != null && !isEnd) widget.rightWidget as Widget, _countDownTimerFormat(), ], ); } /// Builds the UI colons between the time units. Widget _colon({String unit = ":"}) { return Row( children: [ SizedBox( width: widget.spacerWidth, ), Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ Text( unit.tr, style: widget.colonsTextStyle, ), if (widget.enableDescriptions) const SizedBox( height: 5, ), if (widget.enableDescriptions) Text( "", style: widget.descriptionTextStyle, ), ], ), SizedBox( width: widget.spacerWidth, ), ], ); } /// Builds the timer days with its description. Widget _days(BuildContext context) { return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( countdownDays.tr, style: widget.timeTextStyle, ), if (widget.enableDescriptions) const SizedBox(height: 5), if (widget.enableDescriptions) Text( widget.daysDescription.tr, style: widget.descriptionTextStyle, ), ], ); } /// Builds the timer hours with its description. Widget _hours(BuildContext context) { return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( countdownHours.tr, style: widget.timeTextStyle, ), if (widget.enableDescriptions) const SizedBox(height: 5), if (widget.enableDescriptions) Text( widget.hoursDescription.tr, style: widget.descriptionTextStyle, ), ], ); } /// Builds the timer minutes with its description. Widget _minutes(BuildContext context) { return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( countdownMinutes.tr, style: widget.timeTextStyle, ), if (widget.enableDescriptions) const SizedBox(height: 5), if (widget.enableDescriptions) Text( widget.minutesDescription.tr, style: widget.descriptionTextStyle, ), ], ); } /// Builds the timer seconds with its description. Widget _seconds(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ Text( countdownSeconds.tr, style: widget.timeTextStyle, ), if (widget.enableDescriptions) const SizedBox(height: 5), if (widget.enableDescriptions) Text( widget.secondsDescription.tr, style: widget.descriptionTextStyle, ), ], ); } /// When the selected [CountDownTimerFormat] is leaving out the last unit, this function puts the UI value of the unit before up by one. /// /// This is done to show the currently running time unit. String _twoDigits(int n, String unitType) { switch (unitType) { case "minutes": if (widget.format == CountDownTimerFormat.daysHoursMinutes || widget.format == CountDownTimerFormat.hoursMinutes || widget.format == CountDownTimerFormat.minutesOnly) { if (difference > Duration.zero) { n++; } } if (n >= 10) return "$n"; return "0$n"; case "hours": if (widget.format == CountDownTimerFormat.daysHours || widget.format == CountDownTimerFormat.hoursOnly) { if (difference > Duration.zero) { n++; } } if (n >= 10) return "$n"; return "0$n"; case "days": if (widget.format == CountDownTimerFormat.daysOnly) { if (difference > Duration.zero) { n++; } } if (n >= 10) return "$n"; return "0$n"; default: if (n >= 10) return "$n"; return "0$n"; } } /// Convert [Duration] in days to String for UI. String _durationToStringDays(Duration duration) { return _twoDigits(duration.inDays, "days").toString(); } /// Convert [Duration] in hours to String for UI. String _durationToStringHours(Duration duration) { if (widget.format == CountDownTimerFormat.hoursMinutesSeconds || widget.format == CountDownTimerFormat.hoursMinutes || widget.format == CountDownTimerFormat.hoursOnly) { return _twoDigits(duration.inHours, "hours"); } else return _twoDigits(duration.inHours.remainder(24), "hours").toString(); } /// Convert [Duration] in minutes to String for UI. String _durationToStringMinutes(Duration duration) { if (widget.format == CountDownTimerFormat.minutesSeconds || widget.format == CountDownTimerFormat.minutesOnly) { return _twoDigits(duration.inMinutes, "minutes"); } else return _twoDigits(duration.inMinutes.remainder(60), "minutes"); } /// Convert [Duration] in seconds to String for UI. String _durationToStringSeconds(Duration duration) { if (widget.format == CountDownTimerFormat.secondsOnly) { return _twoDigits(duration.inSeconds, "seconds"); } else return _twoDigits(duration.inSeconds.remainder(60), "seconds"); } /// Switches the UI to be displayed based on [CountDownTimerFormat]. Widget _countDownTimerFormat() { if (isEnd) { return widget.endWidget == null ? Container() : widget.endWidget as Widget; } switch (widget.format) { case CountDownTimerFormat.daysHoursMinutesSeconds: return Row( mainAxisSize: MainAxisSize.min, children: [ _days(context), _colon(unit: "天"), _hours(context), _colon(unit: ":"), _minutes(context), _colon(unit: ":"), _seconds(context), // Text(":".tr, style: widget.colonsTextStyle), ], ); case CountDownTimerFormat.daysHoursMinutes: return Row( mainAxisSize: MainAxisSize.min, children: [ _days(context), _colon(unit: "天"), _hours(context), _colon(unit: ":"), _minutes(context), ], ); case CountDownTimerFormat.daysHours: return Row( mainAxisSize: MainAxisSize.min, children: [ _days(context), _colon(unit: "天"), _hours(context), ], ); case CountDownTimerFormat.daysOnly: return Row( mainAxisSize: MainAxisSize.min, children: [ _days(context), ], ); case CountDownTimerFormat.hoursMinutesSeconds: return Row( mainAxisSize: MainAxisSize.min, children: [ _hours(context), _colon(unit: ":"), _minutes(context), _colon(unit: ":"), _seconds(context), // Text(":".tr, style: widget.colonsTextStyle), ], ); case CountDownTimerFormat.hoursMinutes: return Row( mainAxisSize: MainAxisSize.min, children: [ _hours(context), _colon(unit: ":"), _minutes(context), ], ); case CountDownTimerFormat.hoursOnly: return Row( mainAxisSize: MainAxisSize.min, children: [ _hours(context), ], ); case CountDownTimerFormat.minutesSeconds: return Row( mainAxisSize: MainAxisSize.min, children: [ _minutes(context), _colon(unit: ":"), _seconds(context), ], ); case CountDownTimerFormat.minutesOnly: return Row( mainAxisSize: MainAxisSize.min, children: [ _minutes(context), ], ); case CountDownTimerFormat.secondsOnly: return Row( mainAxisSize: MainAxisSize.min, children: [ _seconds(context), ], ); default: return Row( mainAxisSize: MainAxisSize.min, children: [ _days(context), _colon(unit: "天"), _hours(context), _colon(unit: ":"), _minutes(context), _colon(unit: ":"), _seconds(context), ], ); } } }
猜你喜欢
网友评论
- 搜索
- 最新文章
- 热门文章