Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: BrnProgressChart 设置颜色,背景色,以及动画无效 #326

Merged
merged 7 commits into from
Sep 22, 2022
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@


import 'package:bruno/bruno.dart';
import 'package:flutter/material.dart';

Expand All @@ -25,13 +23,17 @@ class ProgressChartExampleState extends State<ProgressChartExample> {
height: 44,
),
BrnProgressChart(
key: UniqueKey(),
width: 200,
width: 300,
height: 20,
value: count,
duration: Duration(milliseconds: 500),
colors: [Colors.lightBlueAccent, Colors.blue],
backgroundColor: Colors.grey,
showAnimation: true,
isFromLastValue: true,
brnProgressIndicatorBuilder: (BuildContext context, double value) {
return Text(
'自定义文本:$value',
'自定义:$value',
style: TextStyle(color: Colors.white),
);
},
Expand All @@ -48,6 +50,7 @@ class ProgressChartExampleState extends State<ProgressChartExample> {
value: count,
divisions: 10,
onChanged: (data) {
if (!mounted) return;
setState(() {
count = data;
});
Expand Down
131 changes: 103 additions & 28 deletions lib/src/components/charts/brn_progress_chart/brn_progress_chart.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@


import 'package:bruno/src/components/charts/brn_progress_chart/brn_progress_chart_painter.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

/// 在进度条上展示的 Widget
Expand Down Expand Up @@ -36,6 +37,12 @@ class BrnProgressChart extends StatefulWidget {
/// 是否展示动画,默认 false
final bool showAnimation;

/// 动画时长,默认 Duration(milliseconds: 250)
final Duration duration;

/// 进度条是否从上次的值开始
final bool isFromLastValue;

const BrnProgressChart(
{Key? key,
this.width = 0,
Expand All @@ -46,7 +53,9 @@ class BrnProgressChart extends StatefulWidget {
this.brnProgressIndicatorBuilder,
this.colors = const [Colors.blueAccent, Colors.blue],
this.backgroundColor = Colors.lightBlueAccent,
this.showAnimation = false})
this.showAnimation = false,
this.isFromLastValue = false,
this.duration = const Duration(milliseconds: 250),})
: assert(0 <= value && value <= 1, 'value 必须在 0 到 1 之间'),
super(key: key);

Expand All @@ -59,59 +68,125 @@ class BrnProgressChart extends StatefulWidget {
class BrnProgressChartState extends State<BrnProgressChart>
with SingleTickerProviderStateMixin {
late Animation<double> _animation;
AnimationController? _animationController;
double _value = 0;
late AnimationController _animationController =
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个是不是在init里面初始化好些

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我是觉得用late 会更好点

AnimationController(vsync: this);
double _lastValue = 0;

bool get _isAnimation => widget.showAnimation;

void _initAnimation() {
final double begin = widget.isFromLastValue ? _lastValue : 0;
final double end = widget.value;
final Tween<double> tween = Tween<double>(begin: begin, end: end);
_animationController.duration =
_isAnimation ? widget.duration : Duration.zero;
_animation = tween.animate(_animationController);
_animationController.reset();
_animationController.forward();
_lastValue = end;
}

@override
void initState() {
super.initState();
if (widget.showAnimation) {
_animationController = AnimationController(
vsync: this, duration: Duration(milliseconds: 250));
Tween tween = Tween<double>(begin: 0, end: widget.value);
_animation = tween.animate(_animationController!) as Animation<double>;
_animation.addListener(() {
setState(() {
_value = _animation.value;
});
});
_animationController!.forward();
} else {
_value = widget.value;
_initAnimation();
}

@override
void didUpdateWidget(covariant BrnProgressChart oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.value != widget.value) {
if (_animationController.isAnimating == true) {
_animationController.stop();
}
_initAnimation();
}
}

@override
void dispose() {
_animationController?.dispose();
_animationController.dispose();
super.dispose();
}

Widget _indicatorWidgetBuilder(BuildContext context, double value) {
return Text(
'$value',
style: widget.textStyle,
);
}

@override
Widget build(BuildContext context) {
final double _value = widget.value;
return Stack(
children: <Widget>[
CustomPaint(
size: Size(widget.width, widget.height),
painter: BrnProgressChartPainter(value: _value),
painter: BrnProgressChartPainter(
value: _value,
animation: _animation,
backgroundColor: widget.backgroundColor,
colors: widget.colors,
),
),
Container(
width: widget.width,
height: widget.height,
padding: EdgeInsets.only(left: widget.indicatorLeftPadding),
alignment: Alignment.centerLeft,
child: null != widget.brnProgressIndicatorBuilder
? widget.brnProgressIndicatorBuilder!(context, _value)
: _indicatorWidgetBuilder(context, _value),
child: IndicatorWidgetBuilder(
notifier: _animation,
value: _value,
textStyle: widget.textStyle,
brnProgressIndicatorBuilder: widget.brnProgressIndicatorBuilder,
),
)
],
);
}
}

class IndicatorWidgetBuilder extends StatefulWidget {
const IndicatorWidgetBuilder({
Key? key,
required this.value,
required this.textStyle,
this.notifier,
this.brnProgressIndicatorBuilder,
}) : super(key: key);

final ValueListenable<double>? notifier;
final double value;
final TextStyle textStyle;
final BrnProgressIndicatorBuilder? brnProgressIndicatorBuilder;

@override
State<IndicatorWidgetBuilder> createState() => _IndicatorWidgetBuilderState();
}

class _IndicatorWidgetBuilderState extends State<IndicatorWidgetBuilder> {
late double _value;

void _changeListener() {
final double value = widget.notifier?.value ?? widget.value;
if(!mounted) return;
setState(() {
_value = value;
});
}

@override
void initState() {
super.initState();
_value = widget.value;
widget.notifier?.addListener(_changeListener);
}

@override
void dispose() {
widget.notifier?.removeListener(_changeListener);
super.dispose();
}

@override
Widget build(BuildContext context) {
final BrnProgressIndicatorBuilder? builder =
widget.brnProgressIndicatorBuilder;
return builder?.call(context, _value) ??
Text('文本:$_value', style: widget.textStyle);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

和之前的代码对比来看,文本: 应该是不需要的。🤔
image

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

是的,我处理下

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ class BrnProgressChartPainter extends CustomPainter {
/// 进度值
final double value;

/// 动画
final Animation<double>? animation;

/// 背景色
final Color backgroundColor;

Expand All @@ -20,50 +23,57 @@ class BrnProgressChartPainter extends CustomPainter {

BrnProgressChartPainter(
{this.value = 0.2,
this.animation,
this.colors = const [Color(0xFF1545FD), Color(0xFF0984F9)],
this.backgroundColor = const Color(0x7A90C9FF),
this.radius = 4,
this.alwaysShowRadius = true});
this.alwaysShowRadius = true})
: super(repaint: animation){
assert(colors.isNotEmpty, 'colors must not be empty');
}

@override
void paint(Canvas canvas, Size size) {
final double curValue = animation?.value ?? this.value;
Paint backgroundPaint = Paint()
..color = this.backgroundColor
..style = PaintingStyle.fill;

Rect backgroundRect = Rect.fromLTWH(0, 0, size.width, size.height);
if (this.alwaysShowRadius) {
RRect backgroundRRect = RRect.fromRectAndCorners(backgroundRect,
bottomRight: Radius.circular(value < 1 ? 0 : this.radius),
topRight: Radius.circular(value < 1 ? 0 : this.radius));
bottomRight: Radius.circular(curValue < 1 ? 0 : this.radius),
topRight: Radius.circular(curValue < 1 ? 0 : this.radius));
canvas.drawRRect(backgroundRRect, backgroundPaint);
} else {
canvas.drawRect(backgroundRect, backgroundPaint);
}

Rect progressBarRect = Rect.fromLTWH(0, 0, size.width * value, size.height);
Rect progressBarRect = Rect.fromLTWH(0, 0, size.width * curValue, size.height);

RRect progressBarRRect = RRect.fromRectAndCorners(progressBarRect,
bottomRight: Radius.circular(
1 == value && false == this.alwaysShowRadius ? 0 : this.radius),
1 == curValue && false == this.alwaysShowRadius ? 0 : this.radius),
topRight: Radius.circular(
1 == value && false == this.alwaysShowRadius ? 0 : this.radius));

Shader progressBarShader = LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
tileMode: TileMode.clamp,
colors: (this.colors.length > 1)
? this.colors
: [this.colors[0], this.colors[0]])
.createShader(progressBarRect);
Paint progressBarPaint = Paint()..shader = progressBarShader;
1 == curValue && false == this.alwaysShowRadius ? 0 : this.radius));
final bool isNotSingleColor = colors.length > 1;
Paint progressBarPaint = Paint();
if (isNotSingleColor) {
progressBarPaint.shader = LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
tileMode: TileMode.clamp,
colors: colors)
.createShader(progressBarRect);
} else {
progressBarPaint.color = colors[0];
}

canvas.drawRRect(progressBarRRect, progressBarPaint);
}

@override
bool shouldRepaint(BrnProgressChartPainter oldDelegate) {
return this.value != oldDelegate.value;
return false;
}
}