You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					143 lines
				
				3.5 KiB
			
		
		
			
		
	
	
					143 lines
				
				3.5 KiB
			| 
											3 years ago
										 | import 'dart:math' as math; | ||
|  | 
 | ||
|  | import 'package:flutter/material.dart'; | ||
|  | import 'package:flutter/scheduler.dart'; | ||
|  | 
 | ||
|  | const halfPi = pi / 2; | ||
|  | const pi = math.pi; | ||
|  | 
 | ||
|  | typedef LabelBuilder = Widget Function(double value); | ||
|  | 
 | ||
|  | class RingIndicator extends StatefulWidget { | ||
|  |   const RingIndicator({ | ||
|  |     Key? key, | ||
|  |     this.backgroundColor = Colors.grey, | ||
|  |     this.ringWidth = 10, | ||
|  |     this.startAngel = 0, | ||
|  |     this.endAngel = pi * 2, | ||
|  |     required this.ringColor, | ||
|  |     required this.maxValue, | ||
|  |     this.minValue = 0, | ||
|  |     required this.value, | ||
|  |     this.innerRing, | ||
|  |     this.labelBuilder, | ||
|  |   }) : super(key: key); | ||
|  | 
 | ||
|  |   final Color backgroundColor; | ||
|  |   final double ringWidth; | ||
|  |   final Color ringColor; | ||
|  |   final double startAngel; | ||
|  |   final double endAngel; | ||
|  |   final double maxValue; | ||
|  |   final double minValue; | ||
|  |   final double value; | ||
|  |   final RingIndicator? innerRing; | ||
|  |   final LabelBuilder? labelBuilder; | ||
|  | 
 | ||
|  |   @override | ||
|  |   State<RingIndicator> createState() => _RingIndicatorState(); | ||
|  | } | ||
|  | 
 | ||
|  | class _RingIndicatorState extends State<RingIndicator> { | ||
|  |   double? _value = 0; | ||
|  | 
 | ||
|  |   @override | ||
|  |   Widget build(BuildContext context) { | ||
|  |     var value = _value ?? widget.value; | ||
|  |     var fillAngel = | ||
|  |         ((value - widget.minValue) / (widget.maxValue - widget.minValue)) * (widget.endAngel - widget.startAngel); | ||
|  |     return Center( | ||
|  |       child: SizedBox.expand( | ||
|  |         child: CustomPaint( | ||
|  |           painter: _RingIndicatorPainter( | ||
|  |             backgroundColor: widget.backgroundColor, | ||
|  |             ringWidth: widget.ringWidth, | ||
|  |             startAngel: widget.startAngel, | ||
|  |             endAngel: widget.endAngel, | ||
|  |             ringColor: widget.ringColor, | ||
|  |             fillAngel: fillAngel, | ||
|  |           ), | ||
|  |           child: Stack( | ||
|  |             children: [ | ||
|  |               if (widget.labelBuilder != null) widget.labelBuilder!(value), | ||
|  |             ], | ||
|  |           ), | ||
|  |         ), | ||
|  |       ), | ||
|  |     ); | ||
|  |   } | ||
|  | 
 | ||
|  |   Ticker? ticker; | ||
|  | 
 | ||
|  |   @override | ||
|  |   void didUpdateWidget(RingIndicator oldWidget) { | ||
|  |     super.didUpdateWidget(oldWidget); | ||
|  |     var startTime = DateTime.now(); | ||
|  |     ticker?.stop(); | ||
|  |     ticker = Ticker((_) { | ||
|  |       var diff = DateTime.now().difference(startTime).inMilliseconds; | ||
|  |       if (diff > 300) { | ||
|  |         return ticker?.stop(); | ||
|  |       } | ||
|  |       if (mounted) { | ||
|  |         setState(() { | ||
|  |           _value = oldWidget.value + (widget.value - oldWidget.value) * (diff / 300); | ||
|  |         }); | ||
|  |       } | ||
|  |     }) | ||
|  |       ..start(); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | class _RingIndicatorPainter extends CustomPainter { | ||
|  |   _RingIndicatorPainter({ | ||
|  |     required this.backgroundColor, | ||
|  |     required this.ringWidth, | ||
|  |     required this.ringColor, | ||
|  |     required this.startAngel, | ||
|  |     required this.fillAngel, | ||
|  |     required this.endAngel, | ||
|  |   }) : _paint = Paint() | ||
|  |           ..strokeWidth = ringWidth | ||
|  |           ..style = PaintingStyle.stroke | ||
|  |           ..strokeCap = StrokeCap.round; | ||
|  | 
 | ||
|  |   final Color backgroundColor; | ||
|  |   final double ringWidth; | ||
|  |   final Color ringColor; | ||
|  |   final double startAngel; | ||
|  |   final double fillAngel; | ||
|  |   final double endAngel; | ||
|  | 
 | ||
|  |   final Paint _paint; | ||
|  | 
 | ||
|  |   @override | ||
|  |   void paint(Canvas canvas, Size size) { | ||
|  |     canvas.drawArc( | ||
|  |       Rect.fromCenter( | ||
|  |         center: size.center(Offset.zero), | ||
|  |         width: size.width, | ||
|  |         height: size.height, | ||
|  |       ), | ||
|  |       startAngel - halfPi, | ||
|  |       endAngel - startAngel, | ||
|  |       false, | ||
|  |       _paint..color = backgroundColor, | ||
|  |     ); | ||
|  |     canvas.drawArc( | ||
|  |       Rect.fromCenter( | ||
|  |         center: size.center(Offset.zero), | ||
|  |         width: size.width, | ||
|  |         height: size.height, | ||
|  |       ), | ||
|  |       startAngel - halfPi, | ||
|  |       fillAngel, | ||
|  |       false, | ||
|  |       _paint..color = ringColor, | ||
|  |     ); | ||
|  |   } | ||
|  | 
 | ||
|  |   @override | ||
|  |   bool shouldRepaint(covariant _RingIndicatorPainter oldDelegate) => true; | ||
|  | } |