import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; /// Animated progress bar. Behaves like implicitly animated widget. /// Check basic implicit animated Flutter widgets like [AnimatedContainer] /// It animates [value] changes. /// Requires [duration] to set filling duration timer /// [onEnd] callback to trigger additional actions (e.g. another animation) /// at the end of the current animation /// [color] or [gradient] to fill the progress bar. Only one parameter is allowed. /// Optional [backgroundColor], defaults to transparent /// Optional [width] defaults to 200.0 /// Optional [height] defaults to 10.0 /// Optional [curve] defaults to [Curves.linear] class AnimatedProgressBar extends ImplicitlyAnimatedWidget { const AnimatedProgressBar({ key, required duration, required this.value, this.width = 200.0, this.height = 10.0, this.color, this.gradient, this.backgroundColor = Colors.transparent, curve = Curves.linear, onEnd, }) : super(key: key, duration: duration, curve: curve, onEnd: onEnd); ///progress bar width final double width; ///progress bar height final double height; ///current progress value final double? value; ///progress bar gradient parameter final Gradient? gradient; ///progress bar color parameter final Color? color; ///progress bar color parameter final Color backgroundColor; @override AnimatedWidgetBaseState createState() => _AnimatedBarState(); } class _AnimatedBarState extends AnimatedWidgetBaseState { Tween? _progressValue; @override void forEachTween(TweenVisitor visitor) { _progressValue = visitor(_progressValue, widget.value, (value) => Tween(begin: value)) as Tween?; } @override Widget build(BuildContext context) { return ProgressBar( value: _progressValue?.evaluate(animation), width: widget.width, height: widget.height, gradient: widget.gradient, color: widget.color, backgroundColor: widget.backgroundColor, ); } @override void debugFillProperties(DiagnosticPropertiesBuilder description) { super.debugFillProperties(description); description.add(DiagnosticsProperty('progressValue', _progressValue, showName: false, defaultValue: null)); } } class ProgressBar extends StatelessWidget { const ProgressBar({ Key? key, required this.value, this.width = 200.0, this.height = 10.0, this.color, this.backgroundColor = Colors.transparent, this.gradient, }) : assert( gradient == null || color == null, 'Cannot provide both a color and a gradient', ), assert( gradient != null || color != null, 'Need to provide color or gradient', ), super(key: key); ///progress bar width final double width; ///progress bar height final double height; ///current progress value final double? value; ///progress bar gradient parameter final Gradient? gradient; ///progress bar color parameter final Color? color; ///progress bar color parameter final Color backgroundColor; @override Widget build(BuildContext context) { return CustomPaint( size: Size(width, height), foregroundPainter: ProgressPainter( value: value!, color: color, gradient: gradient, ), painter: BackgroundPainter( backgroundColor: backgroundColor, ), ); } } class BackgroundPainter extends CustomPainter { const BackgroundPainter({required this.backgroundColor}); ///progress bar backgroundColor final Color backgroundColor; @override void paint(Canvas canvas, Size size) { Paint paint = Paint()..color = backgroundColor; canvas.drawRRect(RRect.fromRectAndRadius(Offset.zero & size, Radius.circular(6)), paint); } @override bool shouldRepaint(covariant BackgroundPainter oldDelegate) => false; } class ProgressPainter extends CustomPainter { const ProgressPainter({required this.value, this.gradient, this.color}); ///current progress bar value final double value; ///progress bar gradient infill final Gradient? gradient; ///progress bar gradient color final Color? color; @override void paint(Canvas canvas, Size size) { Paint paint = Paint(); if (gradient != null) { paint.shader = gradient?.createShader(Offset.zero & size); } if (color != null) { paint.color = color!; } canvas.clipRRect(RRect.fromRectAndRadius(Offset.zero & size, Radius.circular(6))); canvas.drawRRect(RRect.fromRectAndRadius(Rect.fromLTRB(0, 0, size.width * value, size.height), Radius.circular(6)), paint); } @override bool shouldRepaint(covariant ProgressPainter oldDelegate) { return value != oldDelegate.value; } }