how to make Percent Indicator change color programmatically in flutter?
Solution 1
thanks for the response. I also came up with other solution and I think I'm good on what I've ended up with. btw here's what I came up with:
import 'package:flutter/material.dart';
import 'package:percent_indicator/circular_percent_indicator.dart';
class RoutinePage extends StatefulWidget {
@override
_RoutinePageState createState() => _RoutinePageState();
}
class _RoutinePageState extends State<RoutinePage> {
double progress = 0;
currentProgressColor() {
if (progress >= 0.6 && progress < 0.8) {
return Colors.orange;
}
if(progress >= 0.8){
return Colors.red;
}
else{
return Colors.green;
}
}
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Container(
color: Colors.white,
alignment: Alignment(0, 0),
child: CircularPercentIndicator(
animationDuration: 200,
animateFromLastPercent: true,
arcType: ArcType.FULL,
arcBackgroundColor: Colors.black12,
backgroundColor: Colors.white,
progressColor: currentProgressColor(),
percent: progress,
animation: true,
radius: 250.0,
lineWidth: 12.0,
circularStrokeCap: CircularStrokeCap.butt,
),
),
Container(
alignment: Alignment(0, 0),
child: Text(
"${this.progress * 100}%",
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
),
),
),
Container(
alignment: Alignment(0.3, 0.5),
child: RaisedButton(
color: Colors.green,
onPressed: () {
final updated = ((this.progress + 0.1).clamp(0.0, 1.0) * 100);
setState(() {
this.progress = updated.round() / 100;
});
print(progress);
},
child: Text(
'+10%',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
),
)),
),
Container(
alignment: Alignment(-0.3, 0.5),
child: RaisedButton(
color: Colors.red,
onPressed: () {
final updated = ((this.progress - 0.1).clamp(0.0, 1.0) * 100);
setState(() {
this.progress = updated.round() / 100;
});
print(progress);
},
child: Text(
'-10%',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
),
)),
),
],
);
}
}
Solution 2
One of possible solutions is AnimatedBuilder
.
I will show you how can we change color of button and you can easily apply approach to progress indicator.
The example below just shows when tap on button start changing animation. Same for you when you need to start progress bat, just run animationController
and check result.
If you have further questions, do not hesitate to ask in comments
@override
void initState() {
_animationController =
AnimationController(vsync: this, duration: Duration(milliseconds: 300));
_colorTween = ColorTween(begin: Colors.red, end: Colors.green)
.animate(_animationController);
super.initState();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _colorTween,
builder: (context, child) => RaisedButton(
child: Text("Change my color"),
color: _colorTween.value,
onPressed: () {
if (_animationController.status == AnimationStatus.completed) {
_animationController.reverse();
} else {
_animationController.forward();
}
},
),
);
}
Related videos on Youtube
Jang Delos Santos
Updated on June 04, 2022Comments
-
Jang Delos Santos almost 2 years
I'm using a package called percent indicator https://pub.dev/packages/percent_indicator
and I'm currently using its CircularPercentIndicator()
I'm just wondering how to change the progress color when a certain percentage met?
For example: I have a starting progress color of green at 0% when reaching 60% progress color should change to orange and when reaching 80% color should be red.
here's what I got at the moment:
import 'package:flutter/material.dart'; import 'package:percent_indicator/circular_percent_indicator.dart'; class RoutinePage extends StatefulWidget { @override _RoutinePageState createState() => _RoutinePageState(); } class _RoutinePageState extends State<RoutinePage> { double progress = 0; @override Widget build(BuildContext context) { return Stack( children: <Widget>[ Container( color: Colors.white, alignment: Alignment(0, 0), child: CircularPercentIndicator( animationDuration: 100, animateFromLastPercent: true, arcType: ArcType.FULL, arcBackgroundColor: Colors.black12, backgroundColor: Colors.white, progressColor: Colors.green, percent: progress, animation: true, radius: 250.0, lineWidth: 12.0, circularStrokeCap: CircularStrokeCap.round, ), ), Container( alignment: Alignment(0, 0), child: Text("${this.progress * 100}%", style: TextStyle( fontSize: 30, fontWeight: FontWeight.bold, ), ), ), Container( alignment: Alignment(0.3, 0.5), child: RaisedButton( color: Colors.green, onPressed: () { final updated = ((this.progress + 0.1).clamp(0.0, 1.0) * 100); setState(() { this.progress = updated.round() / 100; }); print(progress); }, child: Text('+10%', style: TextStyle( fontWeight: FontWeight.bold, color: Colors.white, ),)), ), Container( alignment: Alignment(-0.3, 0.5), child: RaisedButton( color: Colors.red, onPressed: () { final updated = ((this.progress - 0.1).clamp(0.0, 1.0) * 100); setState(() { this.progress = updated.round() / 100; }); print(progress); }, child: Text('-10%', style: TextStyle( fontWeight: FontWeight.bold, color: Colors.white, ),)), ), ], ); } }
and I don't know if this will help but this is the code of CircularPercentIndicator()
//import 'dart:math'; import 'package:flutter/material.dart'; import 'package:vector_math/vector_math_64.dart' as math; enum CircularStrokeCap { butt, round, square } enum ArcType { HALF, FULL, } class CircularPercentIndicator extends StatefulWidget { ///Percent value between 0.0 and 1.0 final double percent; final double radius; ///Width of the line of the Circle final double lineWidth; ///Color of the background of the circle , default = transparent final Color fillColor; ///First color applied to the complete circle final Color backgroundColor; Color get progressColor => _progressColor; Color _progressColor; ///true if you want the circle to have animation final bool animation; ///duration of the animation in milliseconds, It only applies if animation attribute is true final int animationDuration; ///widget at the top of the circle final Widget header; ///widget at the bottom of the circle final Widget footer; ///widget inside the circle final Widget center; final LinearGradient linearGradient; ///The kind of finish to place on the end of lines drawn, values supported: butt, round, square final CircularStrokeCap circularStrokeCap; ///the angle which the circle will start the progress (in degrees, eg: 0.0, 45.0, 90.0) final double startAngle; /// set true if you want to animate the linear from the last percent value you set final bool animateFromLastPercent; /// set false if you don't want to preserve the state of the widget final bool addAutomaticKeepAlive; /// set the arc type final ArcType arcType; /// set a circular background color when use the arcType property final Color arcBackgroundColor; /// set true when you want to display the progress in reverse mode final bool reverse; /// Creates a mask filter that takes the progress shape being drawn and blurs it. final MaskFilter maskFilter; CircularPercentIndicator( {Key key, this.percent = 0.0, this.lineWidth = 5.0, this.startAngle = 0.0, @required this.radius, this.fillColor = Colors.transparent, this.backgroundColor = const Color(0xFFB8C7CB), Color progressColor, this.linearGradient, this.animation = false, this.animationDuration = 500, this.header, this.footer, this.center, this.addAutomaticKeepAlive = true, this.circularStrokeCap, this.arcBackgroundColor, this.arcType, this.animateFromLastPercent = false, this.reverse = false, this.maskFilter}) : super(key: key) { if (linearGradient != null && progressColor != null) { throw ArgumentError( 'Cannot provide both linearGradient and progressColor'); } _progressColor = progressColor ?? Colors.red; assert(startAngle >= 0.0); if (percent < 0.0 || percent > 1.0) { throw Exception("Percent value must be a double between 0.0 and 1.0"); } if (arcType == null && arcBackgroundColor != null) { throw ArgumentError('arcType is required when you arcBackgroundColor'); } } @override _CircularPercentIndicatorState createState() => _CircularPercentIndicatorState(); } class _CircularPercentIndicatorState extends State<CircularPercentIndicator> with SingleTickerProviderStateMixin, AutomaticKeepAliveClientMixin { AnimationController _animationController; Animation _animation; double _percent = 0.0; @override void dispose() { if (_animationController != null) { _animationController.dispose(); } super.dispose(); } @override void initState() { if (widget.animation) { _animationController = AnimationController( vsync: this, duration: Duration(milliseconds: widget.animationDuration)); _animation = Tween(begin: 0.0, end: widget.percent).animate(_animationController) ..addListener(() { setState(() { _percent = _animation.value; }); }); _animationController.forward(); } else { _updateProgress(); } super.initState(); } @override void didUpdateWidget(CircularPercentIndicator oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.percent != widget.percent || oldWidget.startAngle != widget.startAngle) { if (_animationController != null) { _animationController.duration = Duration(milliseconds: widget.animationDuration); _animation = Tween( begin: widget.animateFromLastPercent ? oldWidget.percent : 0.0, end: widget.percent) .animate(_animationController); _animationController.forward(from: 0.0); } else { _updateProgress(); } } } _updateProgress() { setState(() { _percent = widget.percent; }); } @override Widget build(BuildContext context) { super.build(context); var items = List<Widget>(); if (widget.header != null) { items.add(widget.header); } items.add(Container( height: widget.radius + widget.lineWidth, width: widget.radius, child: CustomPaint( painter: CirclePainter( progress: _percent * 360, progressColor: widget.progressColor, backgroundColor: widget.backgroundColor, startAngle: widget.startAngle, circularStrokeCap: widget.circularStrokeCap, radius: (widget.radius / 2) - widget.lineWidth / 2, lineWidth: widget.lineWidth, arcBackgroundColor: widget.arcBackgroundColor, arcType: widget.arcType, reverse: widget.reverse, linearGradient: widget.linearGradient, maskFilter: widget.maskFilter), child: (widget.center != null) ? Center(child: widget.center) : Container(), ))); if (widget.footer != null) { items.add(widget.footer); } return Material( color: widget.fillColor, child: Container( child: Column( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: items, )), ); } @override bool get wantKeepAlive => widget.addAutomaticKeepAlive; } class CirclePainter extends CustomPainter { final Paint _paintBackground = Paint(); final Paint _paintLine = Paint(); final Paint _paintBackgroundStartAngle = Paint(); final double lineWidth; final double progress; final double radius; final Color progressColor; final Color backgroundColor; final CircularStrokeCap circularStrokeCap; final double startAngle; final LinearGradient linearGradient; final Color arcBackgroundColor; final ArcType arcType; final bool reverse; final MaskFilter maskFilter; CirclePainter( {this.lineWidth, this.progress, @required this.radius, this.progressColor, this.backgroundColor, this.startAngle = 0.0, this.circularStrokeCap = CircularStrokeCap.round, this.linearGradient, this.reverse, this.arcBackgroundColor, this.arcType, this.maskFilter}) { _paintBackground.color = backgroundColor; _paintBackground.style = PaintingStyle.stroke; _paintBackground.strokeWidth = lineWidth; if (arcBackgroundColor != null) { _paintBackgroundStartAngle.color = arcBackgroundColor; _paintBackgroundStartAngle.style = PaintingStyle.stroke; _paintBackgroundStartAngle.strokeWidth = lineWidth; } _paintLine.color = progressColor; _paintLine.style = PaintingStyle.stroke; _paintLine.strokeWidth = lineWidth; if (circularStrokeCap == CircularStrokeCap.round) { _paintLine.strokeCap = StrokeCap.round; } else if (circularStrokeCap == CircularStrokeCap.butt) { _paintLine.strokeCap = StrokeCap.butt; } else { _paintLine.strokeCap = StrokeCap.square; } } @override void paint(Canvas canvas, Size size) { final center = Offset(size.width / 2, size.height / 2); canvas.drawCircle(center, radius, _paintBackground); if (maskFilter != null) { _paintLine.maskFilter = maskFilter; } if (linearGradient != null) { /* _paintLine.shader = SweepGradient( center: FractionalOffset.center, startAngle: math.radians(-90.0 + startAngle), endAngle: math.radians(progress), //tileMode: TileMode.mirror, colors: linearGradient.colors) .createShader( Rect.fromCircle( center: center, radius: radius, ), );*/ _paintLine.shader = linearGradient.createShader( Rect.fromCircle( center: center, radius: radius, ), ); } double fixedStartAngle = startAngle; double startAngleFixedMargin = 1.0; if (arcType != null) { if (arcType == ArcType.FULL) { fixedStartAngle = 220; startAngleFixedMargin = 172 / fixedStartAngle; } else { fixedStartAngle = 270; startAngleFixedMargin = 135 / fixedStartAngle; } } if (arcBackgroundColor != null) { canvas.drawArc( Rect.fromCircle(center: center, radius: radius), math.radians(-90.0 + fixedStartAngle), math.radians(360 * startAngleFixedMargin), false, _paintBackgroundStartAngle, ); } if (reverse) { final start = math.radians(360 * startAngleFixedMargin - 90.0 + fixedStartAngle); final end = math.radians(-progress * startAngleFixedMargin); canvas.drawArc( Rect.fromCircle( center: center, radius: radius, ), start, end, false, _paintLine, ); } else { final start = math.radians(-90.0 + fixedStartAngle); final end = math.radians(progress * startAngleFixedMargin); canvas.drawArc( Rect.fromCircle( center: center, radius: radius, ), start, end, false, _paintLine, ); } } @override bool shouldRepaint(CustomPainter oldDelegate) { return true; } }
-
Admin over 2 yearsYour answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.