progress_bar.dart 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. import 'dart:math' as math;
  2. import 'package:flutter/material.dart';
  3. import 'package:flutter/painting.dart';
  4. class CircularProgressBar extends StatefulWidget {
  5. final double percent;
  6. final double radius;
  7. final double width;
  8. final Widget center;
  9. CircularProgressBar({Key key, this.percent = 0.0, this.radius = 50.0, this.width = 10.0, this.center});
  10. @override
  11. State<StatefulWidget> createState() => _State();
  12. }
  13. class _State extends State<CircularProgressBar> with SingleTickerProviderStateMixin, AutomaticKeepAliveClientMixin {
  14. AnimationController _animationController;
  15. Animation _animation;
  16. double _percent = 0.0;
  17. @override
  18. void dispose() {
  19. if (_animationController != null) {
  20. _animationController.dispose();
  21. }
  22. super.dispose();
  23. }
  24. @override
  25. void initState() {
  26. _animationController = AnimationController(vsync: this, duration: Duration(milliseconds: 1000));
  27. _animation = Tween(begin: 0.0, end: widget.percent).animate(
  28. CurvedAnimation(parent: _animationController, curve: Curves.linear),
  29. )..addListener(() {
  30. setState(() {
  31. _percent = _animation.value;
  32. });
  33. });
  34. _animationController.addStatusListener((status) {});
  35. _animationController.forward();
  36. super.initState();
  37. }
  38. @override
  39. void didUpdateWidget(CircularProgressBar oldWidget) {
  40. super.didUpdateWidget(oldWidget);
  41. if (oldWidget.percent != widget.percent) {
  42. if (_animationController != null) {
  43. _animationController.duration = Duration(milliseconds: 1000);
  44. _animation = Tween(begin: 0.0, end: widget.percent).animate(
  45. CurvedAnimation(parent: _animationController, curve: Curves.linear),
  46. );
  47. _animationController.forward(from: 0.0);
  48. } else {
  49. _updateProgress();
  50. }
  51. }
  52. }
  53. _updateProgress() {
  54. setState(() {
  55. _percent = widget.percent;
  56. });
  57. }
  58. @override
  59. bool get wantKeepAlive => true;
  60. @override
  61. Widget build(BuildContext context) {
  62. super.build(context);
  63. return Container(
  64. height: widget.radius * 2 + widget.width,
  65. width: widget.radius * 2,
  66. child: AnimatedBuilder(
  67. animation: _animation,
  68. builder: (BuildContext context, Widget child) {
  69. return Padding(
  70. padding: const EdgeInsets.symmetric(vertical: 10.0),
  71. child: CustomPaint(
  72. painter: ProgressBarThree(_animation.value, width: widget.width, radius: widget.radius - widget.width / 2),
  73. child: (widget.center != null) ? Center(child: widget.center) : Container(),
  74. ),
  75. );
  76. },
  77. ));
  78. }
  79. }
  80. class ProgressBarThree extends CustomPainter {
  81. final double progress;
  82. final double width;
  83. final double radius;
  84. final Paint _bg = Paint()
  85. ..isAntiAlias = true
  86. ..color = const Color(0xfff1f1f1)
  87. ..style = PaintingStyle.stroke;
  88. final List<Paint> _p = [
  89. Paint()
  90. ..isAntiAlias = true
  91. ..color = const Color(0xffFFE600)
  92. ..style = PaintingStyle.stroke,
  93. Paint()
  94. ..isAntiAlias = true
  95. ..color = const Color(0xffFFAA00)
  96. ..style = PaintingStyle.stroke,
  97. Paint()
  98. ..isAntiAlias = true
  99. ..color = const Color(0xffFF7323)
  100. ..style = PaintingStyle.stroke
  101. ];
  102. ProgressBarThree(this.progress, {this.width = 10.0, this.radius = 50.0});
  103. @override
  104. void paint(Canvas canvas, Size size) {
  105. final center = Offset(size.width / 2, size.height / 2);
  106. final rect = Rect.fromCircle(center: center, radius: this.radius);
  107. double max = math.pi * 2;
  108. double start = math.pi * 3 / 2;
  109. _bg.strokeWidth = width;
  110. int split = 3;
  111. double _angleEnd = max / split;
  112. double _endDiff = (_angleEnd - _angleEnd * 0.98) / 2;
  113. start += _endDiff;
  114. double _angle = start;
  115. for (var i = 0; i < split; i++) {
  116. canvas.drawArc(rect, _angle, _angleEnd* 0.98 , false, _bg);
  117. _angle += _angleEnd;
  118. }
  119. double _progress = 1.0 / split;
  120. start = math.pi * 3 / 2;
  121. start += _endDiff;
  122. _angle = start;
  123. double _progressTotal = math.min(this.progress, 1.0);
  124. for (var i = 0; i < split; i++) {
  125. double _percent = _progressTotal / _progress;
  126. _p[i].strokeWidth = width;
  127. canvas.drawArc(rect, _angle, _angleEnd * 0.98 * math.min(_percent, 1.0), false, _p[i]);
  128. _angle += _angleEnd;
  129. _progressTotal -= _progress;
  130. if (_progressTotal < 0) break;
  131. }
  132. }
  133. @override
  134. bool shouldRepaint(CustomPainter oldDelegate) => this != oldDelegate;
  135. }