- CustomPaint
CustomPaint 是一个继承自 SingleChildRenderObjectWidget 的控件,因此我们不能用 setState 的方式来刷新它,但是我们可以通过传值不断刷新build方法取重新绘制它.它需要传入painter结合size属性进行绘制.
return CustomPaint(
size: Size(double.infinity, w(130)),
painter: CurvePainter(),
);
CurvePainter继承了CustomPainter,CustomPainter需要实现两个方法:
class CurvePainter extends CustomPainter {
@override
paint(Canvas canvas, Size size) {
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
paint() 中进行绘制,可以在这获得画布 Canvas 和 画布的大小 Size。
shouldRepaint() 返回 true 才会进行重绘,否则就只会绘制一次。你可以通过一些条件判断来决定是否每次绘制,这样能够节约系统资源。
然后我们开始构思如何如何实现其效果,先抛开动画效果:
- 先绘制一个半圆(考虑半圆不是闭合的,半圆的边线宽度是画笔的strokeWidth)
- 在绘制半圆内的线条半圆
发现结束了,这么简单吗?需要考虑的重点其实是:半圆是百分比组合成的,每一块儿都只是一个圆弧.看一下画圆弧的方法:
drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint)
rect 参数是一个矩形,先跳过,待会说.
startAngle 参数是起始角度.
sweepAngle 参数是扫过的角度.
useCenter 参数是圆弧是否闭合.
paint 是画笔.
注意:角度是通过π来计算的,2π = 360度.起始角度是从三点钟方向顺时针开始.但是我们需要从九点钟方向顺时针开始,也就是我们需要逆时针180度 = -π = -pi(flutter用pi表示π)
那么我们可以这样计算:第一段p1是-pi到百分比弧度,第二段p2开始弧度是p1的结束弧度,扫过的角度就是百分比弧度,依次类推.
Rect rect = Rect.fromCircle(
center: Offset(size.width / 2, size.height), radius: radius);
// 绘制p1
double runningDegree = pi * runningRate;
canvas.drawArc(rect, -pi, runningDegree, false, curvePaint);
// 绘制p2
curvePaint.color = waitingColor;
double waitingDegree = pi * waitingRate;
canvas.drawArc(
rect, -pi * (1 - runningRate), waitingDegree, false, curvePaint);
// 绘制p3
curvePaint.color = maintainingColor;
double maintainingDegree = pi * maintainingRate;
canvas.drawArc(rect, -pi * (1 - runningRate - waitingRate),
maintainingDegree, false, curvePaint);
// 绘制p4
curvePaint.color = breakDownColor;
double breakDownDegree = pi * breakDownRate;
canvas.drawArc(
rect,
-pi * (1 - runningRate - waitingRate - maintainingRate),
breakDownDegree,
false,
curvePaint);
画内部圆弧要知道:它的圆心和画弧度的圆心是一样的.都是x:宽度的一半,y:高度.
/// 画内部圆弧
curvePaint.color = runningColor;
curvePaint.strokeWidth = 1;
Rect insideR = Rect.fromCircle(
center: Offset(size.width / 2, size.height), radius: radius - 30);
canvas.drawArc(insideR, -pi, pi, false, curvePaint);
接下来就是绘制中心文字:
/// 画文字
TextPainter centerTitlePainter = TextPainter(
textAlign: TextAlign.center,
text: TextSpan(
text: centerTitle.toString(),
style:
TextStyle(color: centerTitleColor, fontSize: centerTitleSize)),
textDirection: TextDirection.ltr);
centerTitlePainter.layout(minWidth: 40);
centerTitlePainter.paint(
canvas,
Offset((size.width - centerTitlePainter.width) / 2,
size.height - centerTitlePainter.height - 10));
到这里绘制就结束了,那么如何实现动画效果呢?
**动画效果:**每一段的p1-p4的弧度*当前动画已经执行的比率就是当前动画时刻4段弧度数,直至比率等于1
// 绘制p1
runningRate = runningRate * animValue;
double runningDegree = pi * runningRate;
canvas.drawArc(rect, -pi, runningDegree, false, curvePaint);
animValue就是当前动画的比率.(如果对动画不了解的可以去看看Flutter官网加深印象)
资源下载移步:
https://download.csdn.net/download/qq1377399077/12980300