activity_countdown_view.dart 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import 'dart:async';
  2. import 'package:flutter/material.dart';
  3. class ActivityCountdownView extends StatefulWidget {
  4. final Duration duration;
  5. final TextStyle? textStyle;
  6. final BoxDecoration? timeBgBoxDecoration;
  7. final double? timeItemWidth;
  8. final double? timeItemHeight;
  9. final BoxFit bgFit;
  10. final EdgeInsetsGeometry contentPadding;
  11. final Widget? separator;
  12. final VoidCallback? onFinish;
  13. const ActivityCountdownView({
  14. super.key,
  15. required this.duration,
  16. this.timeBgBoxDecoration,
  17. this.textStyle,
  18. this.timeItemWidth,
  19. this.timeItemHeight,
  20. this.bgFit = BoxFit.contain,
  21. this.contentPadding = const EdgeInsets.all(4),
  22. this.separator,
  23. this.onFinish,
  24. });
  25. @override
  26. State<ActivityCountdownView> createState() => _ActivityCountdownViewState();
  27. }
  28. class _ActivityCountdownViewState extends State<ActivityCountdownView> {
  29. late Duration _remaining;
  30. Timer? _timer;
  31. @override
  32. void initState() {
  33. super.initState();
  34. _remaining = widget.duration;
  35. _startTimer();
  36. }
  37. void _startTimer() {
  38. _timer = Timer.periodic(const Duration(seconds: 1), (_) {
  39. if (_remaining.inSeconds <= 1) {
  40. _timer?.cancel();
  41. widget.onFinish?.call();
  42. setState(() {
  43. _remaining = const Duration(seconds: 0);
  44. });
  45. } else {
  46. setState(() {
  47. _remaining -= const Duration(seconds: 1);
  48. });
  49. }
  50. });
  51. }
  52. String _twoDigits(int n) => n.toString().padLeft(2, '0');
  53. @override
  54. Widget build(BuildContext context) {
  55. final hours = _twoDigits(_remaining.inHours);
  56. final minutes = _twoDigits(_remaining.inMinutes.remainder(60));
  57. final seconds = _twoDigits(_remaining.inSeconds.remainder(60));
  58. return Row(
  59. mainAxisSize: MainAxisSize.min,
  60. children: [
  61. _buildTimeBox(hours),
  62. _buildSeparator(),
  63. _buildTimeBox(minutes),
  64. _buildSeparator(),
  65. _buildTimeBox(seconds),
  66. ],
  67. );
  68. }
  69. /// 自定义时间数字块,2位合并显示
  70. Widget _buildTimeBox(String text) {
  71. return Container(
  72. width: widget.timeItemWidth,
  73. height: widget.timeItemHeight,
  74. alignment: Alignment.center,
  75. padding: widget.contentPadding,
  76. decoration: widget.timeBgBoxDecoration,
  77. child: Text(
  78. text,
  79. maxLines: 1,
  80. style: widget.textStyle ??
  81. const TextStyle(
  82. fontSize: 20, fontWeight: FontWeight.bold, color: Colors.white),
  83. ),
  84. );
  85. }
  86. /// 自定义分隔符(冒号),如果未设置就给默认间距
  87. Widget _buildSeparator() {
  88. return widget.separator ??
  89. const SizedBox(
  90. width: 4,
  91. );
  92. }
  93. @override
  94. void dispose() {
  95. _timer?.cancel();
  96. super.dispose();
  97. }
  98. }