pargress_bar.dart 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter_screenutil/flutter_screenutil.dart';
  3. class ProgressBar extends StatefulWidget {
  4. final String title;
  5. final int? value;
  6. final Color color;
  7. const ProgressBar({
  8. super.key,
  9. required this.title,
  10. required this.value,
  11. required this.color,
  12. });
  13. @override
  14. State<ProgressBar> createState() => _ProgressBarState();
  15. }
  16. class _ProgressBarState extends State<ProgressBar>
  17. with SingleTickerProviderStateMixin {
  18. late AnimationController _animationController;
  19. late Animation<double> _progressAnimation;
  20. late Tween<double> _valueTween;
  21. @override
  22. void initState() {
  23. super.initState();
  24. _animationController = AnimationController(
  25. vsync: this,
  26. duration: const Duration(seconds: 2),
  27. );
  28. _setupAnimation();
  29. _startAnimation();
  30. }
  31. @override
  32. void didUpdateWidget(covariant ProgressBar oldWidget) {
  33. super.didUpdateWidget(oldWidget);
  34. if (oldWidget.value != widget.value) {
  35. _setupAnimation();
  36. _startAnimation();
  37. }
  38. }
  39. /// 设置动画曲线和范围
  40. void _setupAnimation() {
  41. if (widget.value == null) {
  42. _valueTween = Tween<double>(begin: 0.0, end: 1.0);
  43. } else {
  44. _valueTween = Tween<double>(
  45. begin: 0,
  46. end: _getTargetProgress(),
  47. );
  48. }
  49. _progressAnimation = _valueTween.animate(
  50. CurvedAnimation(parent: _animationController, curve: Curves.easeOut),
  51. );
  52. }
  53. double _getTargetProgress() {
  54. return (widget.value ?? 0) / 100.0;
  55. }
  56. void _startAnimation() {
  57. _animationController.stop();
  58. if (widget.value == null) {
  59. _animationController.repeat();
  60. } else {
  61. _animationController
  62. ..reset()
  63. ..forward();
  64. }
  65. }
  66. @override
  67. void dispose() {
  68. _animationController.dispose();
  69. super.dispose();
  70. }
  71. @override
  72. Widget build(BuildContext context) {
  73. final bool isLoading = widget.value == null;
  74. return Row(
  75. children: [
  76. Text(widget.title),
  77. SizedBox(width: 3.w),
  78. Expanded(
  79. child: Stack(
  80. children: [
  81. // 背景条
  82. Container(
  83. height: 11.h,
  84. decoration: BoxDecoration(
  85. color: widget.color.withOpacity(0.3),
  86. borderRadius: BorderRadius.circular(53.r),
  87. ),
  88. ),
  89. // 动画进度条
  90. AnimatedBuilder(
  91. animation: _progressAnimation,
  92. builder: (_, __) {
  93. final double progress = _progressAnimation.value;
  94. return FractionallySizedBox(
  95. widthFactor: progress.clamp(0.0, 1.0),
  96. child: Container(
  97. height: 11.h,
  98. decoration: BoxDecoration(
  99. color: widget.color,
  100. borderRadius: BorderRadius.circular(53.r),
  101. ),
  102. ),
  103. );
  104. },
  105. ),
  106. // 中间文字
  107. Positioned.fill(
  108. child: Center(
  109. child: Text(
  110. isLoading
  111. ? "加载中..."
  112. : "${(widget.value ?? 0).clamp(0, 100)}%",
  113. style: TextStyle(
  114. color: Colors.white,
  115. fontSize: 7.sp,
  116. fontWeight: FontWeight.w500,
  117. shadows: [
  118. Shadow(
  119. color: Colors.black.withOpacity(0.6),
  120. offset: Offset(1, 1),
  121. blurRadius: 3.r,
  122. ),
  123. ],
  124. ),
  125. ),
  126. ),
  127. ),
  128. ],
  129. ),
  130. ),
  131. ],
  132. );
  133. }
  134. }