使用 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`sfinal 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 descriptionfinal 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;@overridevoid initState() {_startTimer();super.initState();}@overridevoid 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) {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");} elsereturn _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");} elsereturn _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");} elsereturn _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),],);}}}