pargress_bar.dart 3.9 KB

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